Channel注册分为ServerSocketChannel和SockerChannel注册,服务端启动的时候会先进行ServerSocketChannel的注册,启动完成后,每当有一个客户端连接过来,会进行一次SocketChannel注册。
ServerSocketChannel注册
在完成channel的创建以及初始化之后,接下来进行channel的注册过程。
先看下config():
config是ServerBootstrap的成员变量实例ServerBootstrapConfig。ServerBootstrap在前面的准备工作完成了一系列的赋值操作。
group():
进入到了ServerBootstrapConfig的父类AbstractBootstrapConfig的group()方法,继续往下执行:
这个group,就是serverBootstrap.group(bossGroup,workerGroup)传进来的bossGroup。
register(channel):
进入到了NioEventLoopGroup的父类MultithreadEventLoopGroup的register(channel)方法,next()跟进去后,最终来到了MultithreadEventLoopGroup的父类MultithreadEventExecutorGroup的next()方法:
这边会返回一个EventExecutor,实际返回的是一个NioEventLoop实例(EventLoop是EventExecutor的子类)。关于选择器chooser的创建及初始化详见服务端初始化过程(待补充)。
在回到MultithreadEventLoopGroup的register(channel)方法,跟进去:
来到了NioEventLoop的父类SIngleThreadEventLoop的register(channel)方法,再跟进去:
进入到promise.channel().unsafe().register(this, promise)的register(this, promise)中:
跟进run()方法中的register0(promise):
跟进doRegister():
回到register0(promise)方法往下执行,将registered设为true,跟进pipeline.invokeHandlerAddedIfNeeded():
跟进callHandlerAddedForAllHandlers()方法:
再回到register0(promise)方法往下执行
跟进pipeline.fireChannelRegistered():
跟进channelRegistered(this):
跟进ctx.fireChannelRegistered():
在这边ServerSocketChannel对应的pipeline中,HeadContext的下一个入站context对象直接是TailContext。
继续跟进:
这里为什么是空的?因为TailContext已经是pipeline的最后一站了,所以不需要继续往后面传递。
SocketChannel注册
参见ServerBootstrapAcceptor源码分析,流程进入到MultithreadEventLoopGroup的register(channel)方法:
从workerGroup拿到一个NioEventLoop后进行register(channel):
NioSocketChannel的interest set 为什么也是0呢?不着急,先往下看。
回到register0(promise):
跟进pipeline.fireChannelRegistered():
本来应该执行LengthFieldBasedFrameDecoder这个handler的channelRegistered(ctx)方法,所以在这里实现了用户自定义handler的channelRegistered(ctx)方法的调用,但是因为LengthFieldBasedFrameDecoder没有重写,所以进入了父类方法:
又到了前面重复的流程,直到pipeline的最后一站TailContext。
至此完成pipeline.fireChannelRegistered()。
继续往下执行
跟进pipeline.fireChannelActive()看一看:
到目前为止,和pipeline.fireChannelRegister()没什么不一样,重点看readIfIsAutoRead()方法,跟进去:
发现来到了handler的read(ctx)方法,如果子类没有重写这个方法,则调用父类ChannelOutboundHandlerAdapter的read(ctx)方法。
会重复上面的流程,直到pipeline中最前面的那个出站context,就是HeadContext实例,直接到HeadContex看一下:
终于,我们发现NioSocketChannel的interest set由0设为了1。