首先看一下Reactor模型的流程图
整个IO事件的流程是
- 读消息,从通道读取消息
- 数据解码
- 数据处理,handler
- 数据编码
- 写消息,把消息写到通道
我们程序猿一般开发就是handle。
它像一条管道,将绑定到一个通道的多个handler处理器实例串在一起,形成一条流水线。
ChannelPipeline的默认实现,实际上被设计成一个双向链表。
这里注意的是流水线中handler处理的顺序: 入站流程,是从前向后处理,出站流程,是从后向前处理。
这个应该比较好理解,比如注册登录功能,首先需要一个处理器去校验一下用户是否已经是注册用户,如果是注册用户,然后在到登录处理器,执行真正登录的逻辑。
channelPipeline 和 channel 之间的关系是什么样的呢?
一个Netty通道拥有一个ChannelPipeline通道流水线的成员属性,该属性的名称叫做pipeline。从而进行一一绑定。
我们都知道,pipeline中可以添加多个处理器,不管是入站还是出站的handler,都可以添加多个。
那么,handler是如何和pipeline进行绑定的呢?
在Netty的设计中,handler是无状态的,不保存和Channel有关的信息,仅仅是处理逻辑。 而pipeline是由状态的,它和通道一一进行绑定,
那么一个有状态另一个无状态,如何进行绑定的呢? ChannelPipelineContext
我们的处理器是被包装在上下文ChannelPipelineContext中的。
Channel channel(); // 通道
EventExecutor executor();
String name();
ChannelHandler handler(); // 执行器
boolean isRemoved();
ChannelHandlerContext fireChannelRegistered();
ChannelHandlerContext fireChannelUnregistered();
ChannelHandlerContext fireChannelActive();
ChannelHandlerContext fireChannelInactive();
ChannelHandlerContext fireExceptionCaught(Throwable var1);
ChannelHandlerContext fireUserEventTriggered(Object var1);
ChannelHandlerContext fireChannelRead(Object var1);
ChannelHandlerContext fireChannelReadComplete();
ChannelHandlerContext fireChannelWritabilityChanged();
ChannelHandlerContext read();
ChannelHandlerContext flush();
ChannelPipeline pipeline(); // 管道
ByteBufAllocator alloc();
/** @deprecated */
@Deprecated
<T> Attribute<T> attr(AttributeKey<T> var1);
/** @deprecated */
@Deprecated
<T> boolean hasAttr(AttributeKey<T> var1);
那么展示的ChannelPipeline的双链表结构是怎样的呢?
channel通道拥有一条ChannelPipeline通道流水线,每一个流水线节点为一个ChannelPipelineContext上下文对象。
在ChannelHandler通道处理器的入站/出站处理方法中,Netty都会传递一个Context上下文实例作为实例的参数。
处理器中的回调代码,可以通过Context实参,在业务处理过程中去获取ChannelPipeline实例或者Channel实例。