在看Netty源码的时候,我们经常会看到Context,Channel,Pipeline,EventLoop,Handler,Selector这些东西,尤其在debug的时候,经常会被这些概念弄得晕头转向,比方说:
pipeline中有context,context中又有handler,context中又有channel,channel中又有pipeline,NioEventLoop中有selector,一个selector管理多个channel,
各种彼此拥有彼此的关系,很乱。
这里我们就简单梳理一下这些对象,我们先按照流程阶段来看一下这些对象都在什么时候创建的,创建了几次。
我们可以在上述每个类的构造方法中都添加断点,来调试看看流程。
1.NioEventLoopGroup初始化
启动ServerBootStrap之前要为其配置线程组,即创建NioEventLoopGroup
<init>:59, NioEventLoopGroup
<init>:59, MultithreadEventLoopGroup
<init>:84, MultithreadEventExecutorGroup->初始化children数组
newChild:127, NioEventLoopGroup->创建每个数组元素,即NioEventLoop初始化
<init>:134, NioEventLoop->指定NioEventLoopGroup为NioEventLoop的parent
openSelector:166, NioEventLoop->然后为每个NioEventLoop打开一个selector
可以看到,这里会根据用户传入的线程数量,创建一个或者多个NioEventLoop
2.ServerBootStrap的启动
1)DefaultChannelPipeline和NioServerSocketChannel的绑定
bind:253, AbstractBootstrap
bind:278, AbstractBootstrap
doBind:282, AbstractBootstrap
initAndRegister:320, AbstractBootstrap
newChannel:38, ReflectiveChannelFactory->用反射工厂创建channel(NioServerSocketChannel)
<init>:74, NioServerSocketChannel
<init>:42, AbstractNioMessageChannel
<init>:84, AbstractNioChannel
<init>:85, AbstractChannel
newChannelPipeline:118, AbstractChannel->创建DefaultChannelPipeline,并把this,即自身这个NioServerSocketChannel作为构造函数的入参传入,这样该DefaultChannelPipeline和NioServerSocketChannel就绑定到一起了
<init>:97, DefaultChannelPipeline->构造HeadContext
<init>:98, DefaultChannelPipeline->构造TailContext
2)context与handler的绑定
initAndRegister:321, AbstractBootstrap
init:169, ServerBootstrap->为Pipeline添加handler
addLast:210, DefaultChannelPipeline->创建DefaultChannelHandlerContext,并且与handler绑定。每次添加handler都会创建context,但这些context都对应当前DefaultChannelPipeline
newContext:120, DefaultChannelPipeline->将DefaultChannelPipeline绑定到context里
addLast:212, DefaultChannelPipeline->维护context链表顺序
----------------------------
这里番外补一下ChannelInitializer的initChannel
register0:510, AbstractChannel$AbstractUnsafe
invokeHandlerAddedIfNeeded:686, DefaultChannelPipeline
execute:1487, DefaultChannelPipeline$PendingHandlerAddedTask
callHandlerAdded0:637, DefaultChannelPipeline
handlerAdded:107, ChannelInitializer
initChannel:115, ChannelInitializer
initChannel:172, ServerBootstrap$1
----------------------------
3)NioServerSocketChannel和NioEventLoop的绑定
initAndRegister:333, AbstractBootstrap
register:86, MultithreadEventLoopGroup
register:74, SingleThreadEventLoop
register:80, SingleThreadEventLoop
register:473, AbstractChannel$AbstractUnsafe->将eventLoop赋值到该AbstractChannel的eventLoop字段
-----------------------------------------------------------------
总结一下几对关系,我们可以通过名字帮助我们记忆
DefaultChannelPipeline vs NioServerSocketChannel
因为叫做DefaultChannelPipeline,所以它就是channel上面的Pipeline,顾名思义,作用相当于channel上的流水线,对channel上的数据进行处理,这个后面说添加handler的时候再提。
NioEventLoop vs NioServerSocketChannel
而NioEventLoop是执行该流水线操作的线程,同时还用它内部的selector去对该channel的事件进行管理。
DefaultChannelHandlerContext vs ChannelHandler
DefaultChannelHandlerContext顾名思义,是保存ChannelHandler的context,所以与ChannelHandler一一对应,context可以看做是ChannelHandler的容器
DefaultChannelPipeline vs ChannelHandler
我们可以用当前的DefaultChannelPipeline添加多个,所以一个DefaultChannelPipeline可以对应多个ChannelHandler
DefaultChannelPipeline vs DefaultChannelHandlerContext
上面说了context与ChannelHandler一一对应,而一个DefaultChannelPipeline可以对应多个ChannelHandler,所以一个DefaultChannelPipeline也对应了多个ChannelHandler
NioServerSocketChannel vs NioEventLoop
一个NioEventLoop可以管理多个SocketChannel,也可以是多个NioEventLoop可以管理多个SocketChannel,一个SocketChannel最多只有一个NioEventLoop处理,但一个NioEventLoop可以处理多个SocketChannel。
但是对于NioServerSocketChannel比较特殊,通常server端只暴露一个端口接收请求,这样也就只会bind一次,那么只有一个NioEventLoop起所用。但是如果暴露多个端口对外提供服务的话,那么就可以用多个NioEventLoop管理多个NioServerSocketChannel。
3.Client发起连接
processSelectedKey:644, NioEventLoop
read:75, AbstractNioMessageChannel$NioMessageUnsafe
doReadMessages:147, NioServerSocketChannel->这里构造NioSocketChannel,把NioServerSocketChannel和jdk的SocketChannel作为构造函数的参数传进去,装载了jdk的真正的SocketChannel同时又绑和NioServerSocketChannel绑定在了一起
<init>:104, NioSocketChannel
<init>:66, AbstractNioByteChannel
<init>:84, AbstractNioChannel
<init>:85, AbstractChannel
newChannelPipeline:118, AbstractChannel->这里又创建了一个DefaultChannelPipeline,并把this,即这个NioSocketChannel作为构造函数入参传入,实现DefaultChannelPipeline和NioSocketChannel的绑定
channelRead:246, ServerBootstrap$ServerBootstrapAcceptor->这里调用ServerBootstrap中自己的handler的channelRead
addLast:210, DefaultChannelPipeline->把ServerBootstrap$ServerBootstrapAcceptor这个handler和该DefaultChannelPipeline一起添加到context中
channelRead:255, ServerBootstrap$ServerBootstrapAcceptor->把该NioSocketChannel注册到一个NioEventLoop上
processSelectedKey:644, NioEventLoop->NioSocketChannel对应的NioEventLoop会处理该channel上的读事件,进而对客户端的读操作进行相应
总结一下,这里和server启动类似,都涉及到channel创建,绑定NioEventLoop处理,添加handler,创建context等等,但是这里不同的是:
DefaultChannelPipeline vs NioSocketChannel
这里绑定的是NioSocketChannel,用来处理client发起的读请求,不像上面server启动,和Pipeline绑定的是NioServerSocketChannel,用来处理client发起的连接事件。
NioEventLoop vs NioSocketChannel
这里也一样,NioEventLoop处理的是NioSocketChannel上的事件,而不是NioServerSocketChannel上的事件。
DefaultChannelHandlerContext vs ChannelHandler
DefaultChannelPipeline vs ChannelHandler
DefaultChannelPipeline vs DefaultChannelHandlerContext
这三个和上面一样
NioSocketChannel vs NioEventLoop
这个和上面类似,一个NioEventLoop可以管理多个NioSocketChannel,也可以是多个NioEventLoop可以管理多个NioSocketChannel,一个NioSocketChannel最多只有一个NioEventLoop处理,但一个NioEventLoop可以处理多个SocketChannel。
但是值得注意的是,当client和server的连接建立成功之后,后面就会一直使用这个NioSocketChannel来进行读写操作,除非再建立其他连接做读写处理。这也是dubbo采用的所谓单一长连接的模式,dubbo客户端和server端之间只保持一个连接,然后一直用这个连接进行通讯(当然视配置而定,如果配置连接数超过1,那么就不是单一长连接了)。