(1) 在ServerBootstrap.bind()绑定相应的地址时,会根据传入的channelClass类创建对应的ChannelFactory,在ServerBootstrap.initAndRegister()方法中
使用ChannelFactory反射实例化NioServerSocketChannel。
(2)初始化NioServerSocketChannel实例之后传入到ServerBootStrap.init(Channel)
设置Channel初始化值,如ChannelOptions,Attributes。
还有利用ChannelInitializer 将原始初始化ChannelHandler加入到Pipeline中
关键也加入了对于新channel接受动作。
这边是利用一个ServerBootstrapAcceptor来监听channelRead事件,将新产生的channel绑定到childGroup (workerGroup),最终是绑定到WorkerGroup中某个EventLoop 中去。
在以上初始化好NioServerSocketChannel之后,进行注册。config().group()其实是返回的parent group,即在我们初始化时,传入的BossGroup。
注:这边再详细说一下绑定过程
group().register(),其实通过代码跟进,它会通过Group中一个next()方法选择NioEventLoopGroup中一个NioEventLoop来具体进行绑定一个Channel对象。因为一个channel只能对应一个Eventloop。
SingleThreadEventLoop中 绑定关键代码如下:
public ChannelFuture register(final ChannelPromise promise) { ObjectUtil.checkNotNull(promise, "promise"); promise.channel().unsafe().register(this, promise); return promise; }复制代码
可以看最终是调用Channel对象下的一个内部类UnSafe对象进行完成注册。
最终的注册动作是将真正的jdk channel绑定到的EventLoop中的Selector中去。每个channel绑定到Selector中之后,就会形成一个SelectionKey,会加入到EvenLoop中的keyset集合中去。方便在循环遍历时检查每个channel的状态。
在BossGroup启动之后,对应的NioEventLoopGroup线程池的NioEventLoop线程就会死循环检查已经绑定到对应的Selector上的Channel的I/O事件。
(1)当没有发生I/O事件时,NioEventLoop线程会一直堵塞在selector.select() 该方法上
(2)一旦有I/O过来之后,就会调用processSelectedKeys()去处理,循环检查SelectedKeys中的每个key,再进入processSelectedKey()。
(3)再调用对应发送符合事件的channel的unsafe.read() 方法。再该方法中会创建对应NioSocketChannel对象。
从上面的小点中可以看出在NioServerSocketChannel发生了I/O事件中初始化了NioSocketChannel对象,下面就是需要将该对象中是如何注册到WorkerGroup中的解释了。
因为在创建NioServerSocketChannel实例是我们在其Pipeline中添加了ServerBootstrapAcceptor的InboundChannelHandler。并且如下图所示,在创建完Channel之后又将会会NioServerSocketChannel的Pipeline的channelread方法。这样在ServerBootstrapAcceptor中的channelread方法也会得到相应的触发。
这样在ServerBootStrap中的ServerBootstrapAcceptor中
的channelRead就会触发,将新生成的channel注册到ChildGroup中去。接下来就会由WorkGroup的EventLoop对channel进行管理。
SeverBootstrapAcceptor也是一个Inbound处理器,用于Server端accept新的客户端连接时,向新生成的socketChannel中添加用户定义的业务处理器。且将新生成的socketChannel注册到WorkerGroup中去。
Unsafe是Channel的内部类,一个Channel对应一个UnSafe。
UnSafe用于处理Channel对应网络IO的底层操作。ChannelHandler处理回调事件时产生的相关网络IO操作最终也会委托给UnSafe执行。
UnSafe接口中定义了socket相关操作,包括SocketAddress获取、Selector注册、网卡端口绑定、socket建联与断连、socket写数据。
其实workgroup与bossgroup在监听I/O事件逻辑是一样(本身就是同一块代码实现),为什么会有不同read效果呢。从上面的分析,BossGroup会通过UnSafe.read()会有Channel实例产生,但是如果是wokergroup就不是这样的。
为什么呢?
那是因为NioServerSocketChannel 和 NioSocketChannel内部对unsafe的实现不一样。次啊会有此区别。每次与socket的交互还是会通过对应channel的unsafe类进行的。这样虽然BossGroup和Woke人Group共享NioEventLoop代码,但是由于其使用的Channel类型对应的UnSafe实现不一样才会导致对read方法调用有不一样的行为。
Bossgroup :
NioMessageUnsafe ---> AbstractNioMessageChannel、NioServerSocketChannel
Workergroup :
NioByteUnsafe ---> AbstractNioByteChannel、NioSocketChannel