版本为 Netty4.1。
概述
Netty 的 ChannelPipeline 和 ChannelHandler 机制类似于 Servlet 和 Filter 过滤器,这类拦截器实际上是职责链模式的一种变形,主要是为了方便事件的拦截和用户业务逻辑的定制。
Servlet Filter 过滤器提供了一种面向对象的模块化机制,用来将公共人物封装到可插入的组件中。这些组件通过 Web 部署配置文件(web.xml)进行声明,无须改动代码即可添加和删除过滤器。可以对应于程序 Servlet 提供的核心功能进行补充,而不破坏原有的功能。
Netty 的 Channel 过滤器实现原理与 Servlet Filter 机制一致,它将 Channel 的数据管道抽象为 ChannelPipeline,消息在 ChannelPipeline 中流动和传递。ChannelPipeline 持有 I/O 事件拦截器 ChannelHandler 的链表,由 ChannelHandler 来对 I/O 事件进行具体的拦截和处理,可以方便地通过新增和删除 ChannelHandler 来实现不同业务逻辑的定制,能够实现对修改封闭和对扩展到支持。
ChannelPipeline
官网API文档:ChannelPipeline
##ChannelPipeline介绍
每一个Channel都拥有自己的ChannelPipeline,它是ChannelHandler的容器,负责ChannelHandler的管理、事件拦截、消息调度。
ChannelPipeline工作原理
ChannelPipeline实际上就是Channel的数据管道,消息从中通过,依次通过每个ChannelHandler并执行相应的处理。
我们通过对ChannelPipeline所持有的ChannelHandler链表进行简单的增删的操作就可以实现不同业务逻辑定制。
下图是Netty API 中ChannelPipeline对事件流的拦截和处理流程的示意图:
I/O Request
via Channel or
ChannelHandlerContext
|
+---------------------------------------------------+---------------+
| ChannelPipeline | |
| \|/ |
| +---------------------+ +-----------+----------+ |
| | Inbound Handler N | | Outbound Handler 1 | |
| +----------+----------+ +-----------+----------+ |
| /|\ | |
| | \|/ |
| +----------+----------+ +-----------+----------+ |
| | Inbound Handler N-1 | | Outbound Handler 2 | |
| +----------+----------+ +-----------+----------+ |
| /|\ . |
| . . |
| ChannelHandlerContext.fireIN_EVT() ChannelHandlerContext.OUT_EVT()|
| [ method call] [method call] |
| . . |
| . \|/ |
| +----------+----------+ +-----------+----------+ |
| | Inbound Handler 2 | | Outbound Handler M-1 | |
| +----------+----------+ +-----------+----------+ |
| /|\ | |
| | \|/ |
| +----------+----------+ +-----------+----------+ |
| | Inbound Handler 1 | | Outbound Handler M | |
| +----------+----------+ +-----------+----------+ |
| /|\ | |
+---------------+-----------------------------------+---------------+
| \|/
+---------------+-----------------------------------+---------------+
| | | |
| [ Socket.read() ] [ Socket.write() ] |
| |
| Netty Internal I/O Threads (Transport Implementation) |
+-------------------------------------------------------------------+
事件处理流程
Netty 中的事件分为 inbound 事件和 outbound 事件。inbound 事件通常由 I/O 线程触发,比如:
- 注册事件 fireChannelRegistered。
- 连接建立事件 fireChannelActive。
- 读事件和读完成事件 fireChannelRead、fireChannelReadComplete。
- 异常通知事件 fireExceptionCaught。
- 用户自定义事件 fireUserEventTriggered。
- Channel 可写状态变化事件 fireChannelWritabilityChanged。
- 连接关闭事件 fireChannelInactive。
outbound 事件通常是由用户主动出发的 I/O 事件,比如:
- 端口绑定 bind。
- 连接服务端 connect。
- 写事件 write。
- 刷新时间 flush。
- 读事件 read。
- 主动断开连接 disconnect。
- 关闭 channel 事件 close。
ChannelHandler
官网API文档:ChannelHandler
ChannelHandler 类似于 Servlet 的 Filter 过滤器,负责对 I/O 事件进行拦截和处理,可以选择性地处理,也可以透传和终止事件的传递。基于 ChannelHandler 接口,用户可以方便地进行业务逻辑定制,比如打印日志,统一封装异常信息等。
ChannelHandler、ChannelInboundHandler 和 ChannelOutboundHandler 接口中,提供了许多方法。在实际使用中,用户往往只需要其中的一两个。为了方便用户使用,有几个抽象类(ChannelHandlerAdapter、ChannelInboundHandlerAdapter、ChannelOutboundHandlerAdapter)提供了一些默认实现,如此用户只需要实现自己关心的方法便可。
ChannelHandler的执行顺序
值得注意的一点是,ChannelHandler的执行顺序与向ChannelPipeline添加时的顺序有关。因此,在进行类似编解码这样前后依赖的操作时,对ChannelHandler添加的顺序要格外注意。
ChannelHandlerAdapter
ChannelHandlerAdapter 抽象类,提供了 ChannelHandler 接口方法的默认实现,以及根据注解判断该类是否可共享的 isSharable 方法。
ChannelInboundHandlerAdapter、ChannelOutboundHandlerAdapter 分别提供了 ChannelInboundHandler 和 ChannelOutboundHandler 的默认实现。以 ChannelInboundHandlerAdapter 为例,其大多数方法的默认实现都是调用 ChannelHandlerContext 的类似方法,作用为向后传递。