为了避免逻辑判断泛滥导致的拓展性受限问题,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
则相反。