在Nio中,服务端在创建时通常会有以下操作:

  1. ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
  2. serverSocketChannel.bind(new InetSocketAddress(666)); //绑定端口
  3. Selector selector = Selector.open(); //创建选择器
  4. serverSocketChannel.configureBlocking(false); //设置非阻塞模式
  5. serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT); //注册到选择器,监听连接事件

在Netty中仅需要使用bind命令即可实现之前在Nio中的复杂操作,以HelloService案例为例,其对应代码如下图所示:
image.png
Bind语句代替了以往Nio的复杂设置

追踪源码,其实现逻辑在 doBind 方法中,核心为 initAndRegister 方法
image.png
源码位置


解析 initAndRegister:

创建服务端Channel:

image.png
总体流程

ChannelFactory 通过反射创建 Channel
image.png

进入 HelloService 中指定的 NioServerSocketChannel 类中查看其源码,在其无参构造方法中通过JDK反射创建出 NIO ServerSocketChannelimage.png

执行完无参构造后,在其有参构造函数中创建TCP参数配置、调用父类构造函数设置阻塞模式
image.png

创建 id、unsafe、pipeLine
image.png

init方法:

主要可分为两部分,前半部分为初始化,后半为注册
image.png
初始化操作

image.png
注册操作一

点击 register0 方法,进行获取通道、注册、调用初始化方法的操作
image.png

promise 对象即为一开始的 regFuture ,safeSetSuccess 方法返回结果后触发回调方法,最终执行 doBind0 方法
image.png

点击doBind0方法,追溯其源码,找到核心方法 invokeBind
image.png

进入 invokeBind,通过判断JDK版本实现 NioServerSocketChannel 的绑定操作
image.png

完成绑定后判断 NioServerSocketChannel 是否可用,如果可用则触发当前 channel 中 pipeline 上所有可用 handler 事件
image.png

进入 readIfIsAutoRead,通过 debug 溯源到 selectionKey.interestOps(interestOps | readInterestOp) 实现事件的关注
image.png

总结:

首先调用 new Channel() 创建服务端的 Channel( 底层为通过 JDK 创建 JDK 的 Channel ),Netty将其包装为一个自己服务端的 Channel,同时会创建一些基本内的组件绑定在此 Channel 上(例如 pipeLine )。然后调用 init () 方法初始化服务端 Channel,该过程最重要的是为服务端Channel添加一个连接处理器。随后调用 register () 方法注册 selector,该过程中 Netty 将JDK底层的Channel注册到事件轮询器上,并将 Netty 的 Channel 作为 Attachment 绑定到对应的 JDK 底层的 Channel 。最后调用 doBind 方法绑定到 JDK 底层的 API,实现对本地端口的监听