首先回顾一下之前做的工作,在netty服务端启动中,详细说明了netty初始化过程的四个步骤:
- 创建服务端channel,调用jdk底层的api创建jdk的channel,之后netty将其包装成自己的channel,并创建一些基本组件绑定到该channel上。
- 初始化服务端channel,创建完成之后会对channel做一些初始化的工作,比如初始化一些基本属性,添加一些逻辑处理器。
- 注册selector,netty将jdk底层的channel注册到事件轮询器selector上面。
- 端口绑定,调用jdk底层api实现对端口的监听。
其中的前两步在创建服务端channel和初始化服务端channel中详细介绍,而本小节该则介绍第三步:注册selector,其主要作用是将jdk底层的channel注册到事件轮询器上。
1. 注册selector总体流程
同样先根据闪电侠给出的整体流程,对注册selector部分有一个整体的认知:
源码部分接着channel的注册与初始化部分,如下图可知,在初始化完成之后有一个注册的部分,此处的代码对应于AbstractChannel类中的register方法,即总体流程中的第一步入口。
2. register(channel)方法
该方法的源码如下:
其中前面几行是if判断,主要的地方有两个:AbstractChannel.this.eventLoop = eventLoop负责将绑定eventLoop线程用于处理只有的请求;register0(promise)则是实际注册的部分,其源码如下:
register0方法主要分析图中标出来的三个地方。
2.1 doRegister()方法
该方法位于AbstractNioChannel类中,其源码如下:
其中javaChannel()方法返回之前通过jdk底层api创建的服务端channel,之后的register部分则是具体的注册,将this注册到eventLoop().selector上面,这里的this是一个AbstractNioChannel对象,我理解是对java底层channel的一个封装。还有一个参数是ops表示注册是关心的时间,0表示不关心任何事件。这样netty通过调用java底层channel的注册方法完成selector的注册。
2.2 invokeHandlerAddedIfNeeded()与fireChannelRegistered()
在register0()方法中,我们讲主要关心三个步骤,除了doRegister之外便是本小节需要展开的部分。
其中2和3部分对应于用户代码的handler部分,这里我们传入了一个ServerHandler,其重写了三个方法,这三个方法在便是与invokeHandlerAddedIfNeeded()、fireChannelRegistered()对应。
将程序运行起来,变可以看到我们在ServerHandler中输出的内容:
3. 小结
-
注册selector时,以register(channel)方法为入口
-
首先绑定线程
-
之后由regiter0完成实际的注册,而注册部分又主要分三步
- 调用jdk底层channel的注册方法完成selector的注册
- invokeHandlerAddedIfNeeded()
- fireChannelRegistered()
-