ChannelPipeline 和 ChannelHandlerContext
ChannelPipeline 接口
当 Channel 被创建时, 它将会被自动地分配一个新的 ChannelPipeline。 这项关联是永久
性的; Channel 既不能附加另外一个 ChannelPipeline, 也不能分离其当前的。 在 Netty 组件
的生命周期中, 这是一项固定的操作, 不需要开发人员的任何干预。
使得事件流经 ChannelPipeline 是 ChannelHandler 的工作, 它们是在应用程序的初始化
或者引导阶段被安装的。 这些对象接收事件、 执行它们所实现的处理逻辑, 并将数据传递给
链中的下一个 ChannelHandler。 它们的执行顺序是由它们被添加的顺序所决定的。
ChannelHandler 的生命周期
在 ChannelHandler 被添加到 ChannelPipeline 中或者被从 ChannelPipeline 中移除时会调
用下面这些方法。 这些方法中的每一个都接受一个 ChannelHandlerContext 参数。
handlerAdded 当把 ChannelHandler 添加到 ChannelPipeline 中时被调用
handlerRemoved 当从 ChannelPipeline 中移除 ChannelHandler 时被调用
exceptionCaught 当处理过程中在 ChannelPipeline 中有错误产生时被调用
ChannelPipeline 中 ChannelHandler
入站和出站 ChannelHandler 可以被安装到同一个 ChannelPipeline 中。 如果一个消息或
者任何其他的入站事件被读取, 那么它会从 ChannelPipeline 的头部开始流动, 最终, 数据
将会到达 ChannelPipeline 的尾端, 届时, 所有处理就都结束了。
数据的出站运动(即正在被写的数据) 在概念上也是一样的。 在这种情况下, 数据将从
ChannelOutboundHandler 链的尾端开始流动, 直到它到达链的头部为止。 在这之后, 出站
数据将会到达网络传输层, 这里显示为 Socket。 通常情况下, 这将触发一个写操作。
如果将两个类别的ChannelHandler都混合添加到同一个ChannelPipeline 中会发生什么。
虽然 ChannelInboundHandle 和 ChannelOutboundHandle 都扩展自 ChannelHandler, 但是
Netty 能区分 ChannelInboundHandler 实现和 ChannelOutboundHandler 实现, 并确保数据只
会在具有相同定向类型的两个 ChannelHandler 之间传递。
ChannelPipeline 上的方法
addFirst、 addBefore、 addAfter、 addLast
将一个 ChannelHandler 添加到 ChannelPipeline 中
remove 将一个 ChannelHandler 从 ChannelPipeline 中移除
replace 将 ChannelPipeline 中的一个 ChannelHandler 替换为另一个 ChannelHandler
get 通过类型或者名称返回 ChannelHandler
context 返回和 ChannelHandler 绑定的 ChannelHandlerContext
names 返回 ChannelPipeline 中所有 ChannelHandler 的名称
ChannelPipeline 的 API 公开了用于调用入站和出站操作的附加方法。
ChannelHandlerContext
通过使用作为参数传递到每个方法的 ChannelHandlerContext, 事件可以被传递给当前
ChannelHandler 链中的下一个 ChannelHandler。 虽然这个对象可以被用于获取底层的
Channel, 但是它主要还是被用于写出站数据。
ChannelHandlerContext 代表了 ChannelHandler 和 ChannelPipeline 之间的关联, 每当有
ChannelHandler 添加到 ChannelPipeline 中时, 都会创建 ChannelHandlerContext。
ChannelHandlerContext 的主要功能是管理它所关联的 ChannelHandler 和在同一个
ChannelPipeline 中的其他 ChannelHandler 之间的交互。
ChannelHandlerContext 有很多的方法, 其中一些方法也存在于 Channel 和
Channel-Pipeline 本身上, 但是有一点重要的不同。如果调用Channel 或者ChannelPipeline 上
的这些方法, 它们将沿着整个 ChannelPipeline 进行传播。 而调用位于 ChannelHandlerContext
上的相同方法, 则将从当前所关联的 ChannelHandler 开始, 并且只会传播给位于该
ChannelPipeline 中的下一个(入站下一个, 出站上一个) 能够处理该事件的 ChannelHandler。
ChannelHandlerContext 的 API
alloc 返回和这个实例相关联的 Channel 所配置的 ByteBufAllocator
bind 绑定到给定的 SocketAddress, 并返回 ChannelFuture
channel 返回绑定到这个实例的 Channel
close 关闭 Channel, 并返回 ChannelFuture
connect 连接给定的 SocketAddress, 并返回 ChannelFuture
deregister 从之前分配的 EventExecutor 注销, 并返回 ChannelFuture
disconnect 从远程节点断开, 并返回 ChannelFuture
executor 返回调度事件的 EventExecutor
fireChannelActive 触发对下一个 ChannelInboundHandler 上的 channelActive()方法(已
连接) 的调用
fireChannelInactive 触发对下一个 ChannelInboundHandler 上的 channelInactive()方法
(已关闭) 的调用
fireChannelRead 触发对下一个 ChannelInboundHandler 上的 channelRead()方法(已接
收的消息) 的调用
fireChannelReadComplete 触发对下一个 ChannelInboundHandler 上的
channelReadComplete()方法的调用
fireChannelRegistered 触发对下一个 ChannelInboundHandler 上的
fireChannelRegistered()方法的调用
fireChannelUnregistered 触发对下一个 ChannelInboundHandler 上的
fireChannelUnregistered()方法的调用
fireChannelWritabilityChanged 触发对下一个 ChannelInboundHandler 上的
fireChannelWritabilityChanged()方法的调用
fireExceptionCaught 触发对下一个 ChannelInboundHandler 上的
fireExceptionCaught(Throwable)方法的调用
fireUserEventTriggered 触发对下一个 ChannelInboundHandler 上的
fireUserEventTriggered(Object evt)方法的调用
handler 返回绑定到这个实例的 ChannelHandler
isRemoved 如果所关联的 ChannelHandler 已经被从 ChannelPipeline 中移除则返回 true
name 返回这个实例的唯一名称
pipeline 返回这个实例所关联的 ChannelPipeline
read 将数据从 Channel 读取到第一个入站缓冲区; 如果读取成功则触发一个
channelRead 事件, 并(在最后一个消息被读取完成后) 通知 ChannelInboundHandler 的
channelReadComplete(ctx)方法
write 通过这个实例写入消息并经过 ChannelPipeline
writeAndFlush 通过这个实例写入并冲刷消息并经过 ChannelPipeline
当使用 ChannelHandlerContext 的 API 的时候, 有以下两点:
ChannelHandlerContext 和 ChannelHandler 之间的关联(绑定) 是永远不会改变的,
所以缓存对它的引用是安全的;
如同我们在本节开头所解释的一样, 相对于其他类的同名方法, ChannelHandler
Context 的方法将产生更短的事件流, 应该尽可能地利用这个特性来获得最大的性能。