目录
在《Netty权威指南》(第二版)中,ChannelPipeline与ChannelHandler之间的关系被李林峰老师比做J2EE中的Servlet和Filter,即ChannelHandler的职能是网络I/O操作的过滤器。我们一起来详细学习它们吧。
ChannelHandler
Netty API : ChannelHandler
ChannelHandler功能介绍
- ChannelHandler的主要功能是为I/O操作进行拦截和处理,我们可以称呼它为:
I/O事件拦截器
。 - 每一个Channel有拥有一个ChannelPipeline,每一个ChannelPipeline中可以包含多个ChannelHandler。
- ChannelHandler可以全部拦截也可以选择性的拦截通过它的信息。对拦截到的信息加以处理后,处理的结果会被传递到ChannelPipeline中的下一个ChannelHandler中执行对应的处理。
通过ChannelHandlerAdapter自定义拦截器
虽然Netty提供了种类丰富的ChannelHandler足以应付许多场景,但在实际项目中远远不够用,这时我们需要封装自己的拦截器。
通常自定义的ChannelHandler只需要继承ChannelHandlerAdapter并覆盖需要用到的方法即可。
ChannelHandlerContext接口
ChannelHandler与ChannelHandlerContext是一一对应的关系,ChannelPipeline并不是直接管理ChannelHandler,而是通过ChannelHandlerContext来间接管理。ChannelHandlerContext通过以下两个方法可以获取到所绑定的Channel和ChannelHandler。
方法名 | 返回类型 | 说明 |
---|---|---|
channel() | Channel | 返回该ChannelHandlerContext所绑定的Channel |
handler() | ChannelHandler | 返回该ChannelHandlerContext所绑定的ChannelHandler |
ChannelPipeline
Netty 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) |
+-------------------------------------------------------------------+
ChannelHandler的执行顺序
值得注意的一点是,ChannelHandler的执行顺序与向ChannelPipeline添加时的顺序有关。因此,在进行类似编解码这样前后依赖的操作时,对ChannelHandler添加的顺序要格外注意。
Netty API :
For example, let us assume that we created the following pipeline.
In the example above, the class whose name starts with Inbound means it is an inbound handler. The class whose name starts with Outbound means it is a outbound handler.
ChannelPipeline p = ...;
p.addLast("1", new InboundHandlerA());
p.addLast("2", new InboundHandlerB());
p.addLast("3", new OutboundHandlerA());
p.addLast("4", new OutboundHandlerB());
p.addLast("5", new InboundOutboundHandlerX());