6.2 ChannelHandlerContext

每次将ChannelHandler添加到ChannelPipeline时,都会创建并分配一个新的ChannelHandlerContext。ChannelHandlerContext允许ChannelHandler与其他ChannelHandler实现进行交互,最后与基础传输进行交互,这些传输是同一ChannelPipeline的一部分。

ChannelHandlerContext永远不会为添加的ChannelHandler更改,因此可以安全地进行缓存。

ChannelHandlerContext实现ChannelInboundInvoker和ChannelOutboundInvoker。它具有许多方法,它们也存在于Channel或ChannelPipeline本身上。区别在于,如果您在Channel或ChannelPipeline上调用它们,则它们始终流经完整的ChannelPipeline。相反,如果在ChannelHandlerContext上调用方法,则该方法从当前位置开始,在可以处理事件的ChannelPipeline中通知临近的ChannelHandler。

6.2.1 通知下一个ChannelHandler

您可以通过调用ChannelInboundInvoker和ChannelOutboundInvoker中列出的各种方法之一来通知同一ChannelPipline中最接近的处理程序。通知从何处开始取决于您如何设置通知。

图6.2显示ChannelHandlerContext如何属于ChannelHandler并将其绑定到ChannelPipeline。

现在,如果您希望事件流遍及整个ChannelPipeline,则有两种不同的方法:

  • Invoke methods on the Channel.

  • Invoke methods on the ChannelPipeline.

两种方法都使事件流过整个ChannelPipeline。它是从头开始还是从头开始主要取决于事件的性质。如果是入站事件,则从头开始,如果是出站事件,则从头开始。

下面的清单显示了如何从最后开始通过ChannelPipeline传递写事件(因为这是出站操作)。

‌ 消息流经整个ChannelPipeline。如前所述,您也可以通过ChannelPipeline执行相同的操作。以下清单显示了这一点。

‌ 消息流经整个ChannelPipeline。每个事件(清单6.2和6.3)在事件流方面都是相等的。您还应该注意,可以通过ChannelHandlerContext访问Channel和ChannelPipeline。

图6.3显示了由Channel或ChannelPipeline触发的通知事件的流程。

在某些情况下,您可能想在ChannelPipeline的特定位置开始,而又不想让它流过整个ChannelPipeline,例如:

  • To save the overhead of passing the event through extra ChannelHandlers that are not interested in it.

  • 排除一些ChannelHandlers。

在这种情况下,您可以使用ChannelHandler的ChannelHandlerContext通知您首选的起点。请注意,它将执行使用的ChannelHandlerContext的下一个ChannelHandler,而不是属于使用的ChannelHandlerContext

清单6.4显示了如何直接使用ChannelHandlerContext进行操作。

消息开始通过下一个ChannelHandler流经ChannelPipeline到达ChanneHandlerContext,在这种情况下,事件流将启动下一个ChannelHandler到所使用的ChannelHandlerContext。

如您所见,它现在从特定的ChannelHandlerContext开始,并跳过之前的所有ChannelHandler。使用ChannelHandlerContext进行操作是一种常见的模式,如果从ChannelHandler实现中调用操作,则使用频率最高。

(一眼看懂的句子词语不再翻译 😃 )

You can also use the ChannelHandlerContext from outside, because its thread-safe.

6.2.2 修改 ChannelPipeline

您可以通过调用pipeline()方法来访问ChannelHandler所属的ChannelPipeline。一个非平凡的应用程序可以在运行时动态地在ChannelPipeline中插入,删除或替换ChannelHandlers。

NOTE You can keep the ChannelHandlerContext for later use, such as triggering an event outside the handler methods, even from a different Thread.

The following listing shows how you can store the ChannelHandlerContext for later use and then use it even from another thread.

Please note that a ChannelHandler instance can be added to more than one ChannelPipeline if its annotated with the @Sharable.This means that a single ChannelHandler instance can have more than one ChannelHandlerContext, and therefore the single instance can be invoked with a different ChannelHandlerContext.

If you try to add a ChannelHandler to more then one ChannelPipeline that is not annotated with @Sharable an exception is thrown. Be aware that once you annotate a ChannelHandler with @Sharable it must be safe to use from different threads and also be safe to use with different channels (connections) at the same time. Lets look at how it should be used. The following listing shows the correct use of the @Sharable annotation.

‌ @Sharable的使用在这里是有效的,因为ChannelHandler不使用任何字段来存储数据,因此它是无状态的。

@Sharable也有不好的用法,如下面的清单所示。

Why is the use of @Sharable wrong here? Its easy to guess once you look at the code. The problem is that were using a field to hold the count of the method calls here. As soon as you add the same instance of the NotSharableHandler to the ChannelPipeline you get bad side effects, such as the count field being accessed and modified by different connections (and possible threads) now.

The rule of thumb is to use @Sharable only if youre sure that you can reuse the ChannelHandler on many different channels

Why share a ChannelHandler ?

You may wonder why you want to even try to share a ChannelHandler and so annotate it with @Sharable, but there are some situation where it can make sense. First off if you can share it you will need to create less Object which the Garbage Collector needs to recycle later. An other use case would be that you want to mantain some global statistics in the ChannelHandler which are updated by all Channels (like concurrent connection count)

最后更新于