Netty启动源码解析
概念
1.handler
源码是这么解析它的
the ChannelHandler to use for serving the requests.
意思是用于服务请求,也就是主reactor线程处理的handler.
重要的实现类
ServerBootstrapAcceptor
这个类在ServerBootstrap启动中有默认加到主reactor的pipeline(默认的pipeline是DefaultChannelPipeline,请记住这个实现类)里。
LoggingHandler
netty提供的一个记录日志handler
childHandler
Set the ChannelHandler which is used to serve the request for the Channel's.
文档指出这是一个处理channel请求的handler
启动流程
1.初始化serverSocket
1.1 创建ServerSocketChannel
具体实现由启动时channel参数决定
1.2 初始化channel
向serverSocketChannel加入ChannelInitializer实例, 在该实例回调中向pipeline中加入启动时加入的handler实例(上文提到的handler参数)和ServerBootstrapAccptor实例
1.3 从bossGroup中取出一个线程来处理channel注册,并注册到线程自己的selector上
- #启动bossGroup线程,在线程里处理事件循环和队列任务,具体逻辑不深入。
- 这里注册到selector的感兴趣事件为0,并没有将accept事件加入到selector中,这里只有启动,和处理任务队列里的数据,只有后面执行bind方法后才能真正处理网络事件。
- 从这里可以得知,我们在许多的bossgroup中取出一个,如果是设定了多个bossGroup线程,并且只绑定到一个网卡,其它线程可能不会被使用,这个问题需要我们思考。
2.doBind0绑定端口
2.1 调用channel的bind方法
2.2 调用channel里的pipeline.bind方法
2.3 从尾结点开始找到所有OUT的handler,并调用bind方法
在header节点会调用unsafe.bind,这里才是netty真正实现的方法
2.3.1 NioMessageUnsafe.bind
2.3.2 doBind绑定网卡和端口
2.3.3 触发fireChannelActive事件
if (!wasActive && isActive()) {
invokeLater(new Runnable() {
@Override
public void run() {
pipeline.fireChannelActive();
}
});
}
2.3.4 从头节点执行active方法
// 找到所有inBound的active方法
ctx.fireChannelActive(); // findContextInbound(MASK_CHANNEL_ACTIVE)
readIfIsAutoRead();
// 调用pipeline.read方法
2.3.4.1 readIfIsAutoRead从pipeline的尾结点开始读取
2.3.4.2 读取到headContext节点
调用headContext.read读取,即调用unsafe.beginRead(),这里的unsafe实现类是NioMessageUnsafe
2.3.4.3 doBeginRead
这里才真正将accept事件加入到selector感兴趣中
final int interestOps = selectionKey.interestOps();
if ((interestOps & readInterestOp) == 0) {
selectionKey.interestOps(interestOps | readInterestOp);
}
3.初始化完成
至此,可以开始接收网络数据。
- 有连接过来,会在bossGroup线程中感知到,具体逻辑在NioEventLoop.run方法中可以查看。
- 具体处理读请求数据的在NioMessageUnsafe.read中
转载自:https://juejin.cn/post/7348981169483055155