2019-05-16 netty 服務(wù)端啟動(dòng)

以netty源碼中的為EchoServer例,分析netty服務(wù)端啟動(dòng)的流程

public final class EchoServer {

    public static void main(String[] args) throws Exception {
        // Configure the server.
        EventLoopGroup bossGroup = new NioEventLoopGroup(1);
        EventLoopGroup workerGroup = new NioEventLoopGroup();
        try {
            ServerBootstrap b = new ServerBootstrap();
            b.group(bossGroup, workerGroup)
                    .channel(NioServerSocketChannel.class)
                    .option(ChannelOption.SO_BACKLOG, 100)
                    .handler(new LoggingHandler(LogLevel.INFO))
                    .childHandler(new ChannelInitializer<SocketChannel>() {
                        @Override
                        public void initChannel(SocketChannel ch) throws Exception {
                            ChannelPipeline p = ch.pipeline();
                            p.addLast(new LoggingHandler(LogLevel.INFO));
                            p.addLast(new EchoServerHandler());
                        }
                    });

            // Start the server.
            ChannelFuture f = b.bind(8007).sync();

            // Wait until the server socket is closed.
            f.channel().closeFuture().sync();
        } finally {
            // Shut down all event loops to terminate all threads.
            bossGroup.shutdownGracefully();
            workerGroup.shutdownGracefully();
        }
    }
}

首先在ServerBootstrap調(diào)用group方法的時(shí)候會(huì)傳進(jìn)去兩組group線程組;


image.png

調(diào)用父類的構(gòu)造器設(shè)置group屬性


image.png

這兩個(gè)group線程會(huì)分別賦給group和childGroup兩個(gè)屬性;


image.png
image.png
image.png

這里的childGroup 是由EventLoopGroup workerGroup = new NioEventLoopGroup()初始化的,默認(rèn)會(huì)創(chuàng)建兩倍cpu核數(shù)的NioEventLoop線程數(shù)量;

image.png

繼續(xù)走調(diào)用channel()方法,會(huì)創(chuàng)建一個(gè)ReflectiveChannelFactory,這里傳進(jìn)去的就是class io.netty.channel.socket.nio.NioServerSocketChannel這個(gè)class;


image.png

同時(shí)設(shè)置channelFactory屬性為為NioServerSocketChannel.class;


image.png

接下來就是設(shè)置一些屬性,handler,childHandler,這里不再展開;

繼續(xù)走,看調(diào)用bind方法的時(shí)候


image.png

最終會(huì)調(diào)用到io.netty.bootstrap.AbstractBootstrap#doBind方法


image.png

調(diào)用initAndRegister 初始化channel并且進(jìn)行注冊(cè)selector;
首先看初始化Channel部分,調(diào)用this.channelFactory.newChannel();方法


image.png
image.png

其實(shí)這里的clazz就是class io.netty.channel.socket.nio.NioServerSocketChannel,其實(shí)創(chuàng)建的channel對(duì)象就是NioServerSocketChannel;

接下來我們?cè)诳纯碞ioServerSocketChannel的構(gòu)造函數(shù)做了什么?

image.png
image.png

調(diào)用newSocket方法,通過jdk底層SelectorProvider.provider().openServerSocketChannel()來創(chuàng)建jdk ServerSocketChannel;

image.png

接下來調(diào)用構(gòu)造函數(shù)初始化屬性配置,其實(shí)就是設(shè)置ServerSocketChannelConfig


image.png

設(shè)置unsafe,id,pipeline等參數(shù),其實(shí)在這里就已經(jīng)確定了這個(gè)channel屬于哪個(gè)pipeline; 客戶端創(chuàng)建channel也是一樣的;


image.png

初始化channel


image.png

配置config


image.png

以下便是這個(gè)config的屬性配置


image.png

以上就是服務(wù)端channel的創(chuàng)建過程,接下來就是服務(wù)端channel的初始化過程
1.設(shè)置option屬性值,把它設(shè)置到config中去


image.png
image.png

2.設(shè)置channel的attr屬性


image.png

3.為pipeline設(shè)置handler,ChannelHandler handler = ServerBootstrap.this.config.handler();去除BootStrap中配置的handler,然后添加到Pipeline中

image.png

4.添加一個(gè)ServerBootstrapAcceptor,其實(shí)這是一個(gè)特殊的channelHandler,
傳入的一個(gè)work線程組,handler,attr和options等屬性;


image.png

channel注冊(cè)到selector


image.png

this.config().group()這個(gè)其實(shí)就是boss線程綁定channel,代碼位置io.netty.channel.AbstractChannel.AbstractUnsafe#register;

image.png

在看register0方法實(shí)現(xiàn)


image.png
image.png

調(diào)用jdk底層進(jìn)行注冊(cè),每隔NioEventLoop都有一個(gè)Selector屬性


image.png

結(jié)下來AbstractChannel.this.pipeline.invokeHandlerAddedIfNeeded();會(huì)調(diào)用到io.netty.channel.DefaultChannelPipeline.PendingHandlerAddedTask#execute從而會(huì)觸發(fā)io.netty.channel.ChannelHandlerAdapter#handlerAdded方法的調(diào)用

這行代碼AbstractChannel.this.pipeline.fireChannelRegistered();會(huì)觸發(fā)
io.netty.channel.ChannelInboundHandler#channelRegistered事件的調(diào)用;

繼續(xù)看doBind方法


image.png

io.netty.channel.AbstractChannel.AbstractUnsafe#bind


image.png

最終通過NioServerSocketChannel 進(jìn)行端口綁定,調(diào)用jdk底層的方法


image.png

最后觸發(fā)ChannelActive事件,調(diào)用readIfIsAutoRead()方法處理客戶端鏈接事件

image.png

感興趣的可以去跟下代碼,這個(gè)read會(huì)在pipeline上不斷的傳播


image.png

有一個(gè)自動(dòng)讀的配置其實(shí)是在初始化ServerBootstrapAcceptor配置的


image.png
image.png
image.png

這里的readInterestOp 其實(shí)就是NioServerSocketChannel構(gòu)造函數(shù)中傳入的16


image.png

到此,服務(wù)端啟動(dòng)的代碼走讀就完了。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容