为了避免逻辑判断泛滥导致的拓展性受限问题,Netty 发明了 pipeline 和 channelHandler 。它通过责任链设计模式来组织代码逻辑,并且能够支持逻辑的动态添加和删除 ,Netty 能够支持各类协议的扩展,比如 HTTP,WebSocket,Redis,靠的就是 pipeline 和 channelHandler。
结构

在 Netty 整个框架里面,一条连接对应着一个 Channel,这条 Channel 所有的处理逻辑都在一个叫做 ChannelPipeline 的对象里面,ChannelPipeline 是一个双向链表结构,他和 Channel 之间是一对一的关系。
ChannelPipeline 里面每个节点都是一个 ChannelHandlerContext 对象,这个对象能够拿到和 Channel 相关的所有的上下文信息,然后这个对象包着一个重要的对象,那就是逻辑处理器 ChannelHandler。
channelHandler 家族

入站操作和数据由 ChannelInboundHandler处理。 在开始组装响应之前的所有的逻辑,都可以放置在 ChannelInboundHandler 里处理,它的一个最重要的方法就是 channelRead()。比如,我们在一端读到一段数据,首先要解析这段数据,然后对这些数据做一系列逻辑处理,最终把响应写到对端。
出站操作和数据将由ChannelOutboundHandler 处理。它是定义我们一端在组装完响应之后,把数据写到对端的逻辑,它里面最核心的一个方法就是 write()。比如,我们封装好一个 response 对象,接下来我们有可能对这个 response 做一些其他的特殊逻辑,然后,再编码成 ByteBuf,最终写到对端。
这两个子接口分别有对应的默认实现,ChannelInboundHandlerAdapter和 ChanneloutBoundHandlerAdapter,它们分别实现了两大接口的所有功能,默认情况下会把读写事件传播到下一个 handler。
事件传播
Netty通过责任链设计模式来组织代码逻辑,所谓的事件传播其实就是事件在ChannelPipeline上移动。
可以看到ChannelPipeline是由一系列ChannelHandlers组成,其还提供了通过自身传播事件的方法,当进站事件触发时,其从ChannelPipeline的头部传递到尾部,而出站事件会从右边传递到左边。
当管道传播事件时,其会确定下一个ChannelHandler的类型是否与移动方向匹配,若不匹配,则会跳过并寻找下一个,直至找到相匹配的ChannelHandler(一个处理器可以会同时实现ChannelInboundHandler和ChannelOutboundHandler)。

关于ChannelInboundHandler 和ChanneloutBoundHandler的传播顺序的不同,可以看下面的例子:
1 | serverBootstrap |
在该例子中,pipeline 的执行顺序是:InBoundHandlerA->InBoundHandlerB()->InBoundHandlerC()->OutBoundHandlerE()
channelPipeline是双向链表,inBoundHandler的事件通常只会传播到下一个inBoundHandler,outBoundHandler的事件通常只会传播到下一个outBoundHandler,两者相互不受干扰。
inBoundHandler 的执行顺序与我们实际的添加顺序相同,而 outBoundHandler 则相反。