在看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,那么就不是单一长连接了)。