以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線程組;

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

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



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

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

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

接下來就是設(shè)置一些屬性,handler,childHandler,這里不再展開;
繼續(xù)走,看調(diào)用bind方法的時(shí)候

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

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


其實(shí)這里的clazz就是class io.netty.channel.socket.nio.NioServerSocketChannel,其實(shí)創(chuàng)建的channel對(duì)象就是NioServerSocketChannel;
接下來我們?cè)诳纯碞ioServerSocketChannel的構(gòu)造函數(shù)做了什么?


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

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

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

初始化channel

配置config

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

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


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

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

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

channel注冊(cè)到selector

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

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


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

結(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方法

io.netty.channel.AbstractChannel.AbstractUnsafe#bind

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

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

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

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



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

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