以netty源码中的为EchoServer例,分析netty服务端启动的流程
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() {
@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调用group方法的时候会传进去两组group线程组;
调用父类的构造器设置group属性
这两个group线程会分别赋给group和childGroup两个属性;
这里的childGroup 是由EventLoopGroup workerGroup = new NioEventLoopGroup()
初始化的,默认会创建两倍cpu核数的NioEventLoop线程数量;
继续走调用channel()方法,会创建一个ReflectiveChannelFactory,这里传进去的就是class io.netty.channel.socket.nio.NioServerSocketChannel这个class;
同时设置channelFactory属性为为NioServerSocketChannel.class;
接下来就是设置一些属性,handler,childHandler,这里不再展开;
继续走,看调用bind方法的时候
最终会调用到io.netty.bootstrap.AbstractBootstrap#doBind方法
调用initAndRegister 初始化channel并且进行注册selector;
首先看初始化Channel部分,调用this.channelFactory.newChannel();方法
其实这里的clazz就是class io.netty.channel.socket.nio.NioServerSocketChannel,其实创建的channel对象就是NioServerSocketChannel;
接下来我们在看看NioServerSocketChannel的构造函数做了什么?
调用newSocket方法,通过jdk底层SelectorProvider.provider().openServerSocketChannel()
来创建jdk ServerSocketChannel;
接下来调用构造函数初始化属性配置,其实就是设置ServerSocketChannelConfig
设置unsafe,id,pipeline等参数,其实在这里就已经确定了这个channel属于哪个pipeline; 客户端创建channel也是一样的;
初始化channel
配置config
以下便是这个config的属性配置
以上就是服务端channel的创建过程,接下来就是服务端channel的初始化过程
1.设置option属性值,把它设置到config中去
2.设置channel的attr属性
3.为pipeline设置handler,ChannelHandler handler = ServerBootstrap.this.config.handler();
去除BootStrap中配置的handler,然后添加到Pipeline中
4.添加一个ServerBootstrapAcceptor,其实这是一个特殊的channelHandler,
传入的一个work线程组,handler,attr和options等属性;
channel注册到selector
this.config().group()
这个其实就是boss线程绑定channel,代码位置io.netty.channel.AbstractChannel.AbstractUnsafe#register;
在看register0方法实现
调用jdk底层进行注册,每隔NioEventLoop都有一个Selector属性
结下来AbstractChannel.this.pipeline.invokeHandlerAddedIfNeeded();
会调用到io.netty.channel.DefaultChannelPipeline.PendingHandlerAddedTask#execute
从而会触发io.netty.channel.ChannelHandlerAdapter#handlerAdded
方法的调用
这行代码AbstractChannel.this.pipeline.fireChannelRegistered();
会触发
io.netty.channel.ChannelInboundHandler#channelRegistered
事件的调用;
继续看doBind方法
io.netty.channel.AbstractChannel.AbstractUnsafe#bind
最终通过NioServerSocketChannel 进行端口绑定,调用jdk底层的方法
最后触发ChannelActive
事件,调用readIfIsAutoRead()
方法处理客户端链接事件
感兴趣的可以去跟下代码,这个read会在pipeline上不断的传播
有一个自动读的配置其实是在初始化ServerBootstrapAcceptor配置的
这里的readInterestOp 其实就是NioServerSocketChannel构造函数中传入的16
到此,服务端启动的代码走读就完了。