以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)行注冊selector赡鲜;
首先看初始化Channel部分,調(diào)用this.channelFactory.newChannel();方法
其實(shí)這里的clazz就是class io.netty.channel.socket.nio.NioServerSocketChannel庐船,其實(shí)創(chuàng)建的channel對象就是NioServerSocketChannel银酬;
接下來我們在看看NioServerSocketChannel的構(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注冊到selector
this.config().group()
這個(gè)其實(shí)就是boss線程綁定channel,代碼位置io.netty.channel.AbstractChannel.AbstractUnsafe#register;
在看register0方法實(shí)現(xiàn)
調(diào)用jdk底層進(jìn)行注冊诽俯,每隔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)的代碼走讀就完了。