Netty in Action筆記(Chapter 6)ChannelHandler

What makes ChannelHandler even more powerful is that you can chain them so each ChannelHandler implementation can fulfill small tasks. This helps you write clean and reusable implementations.前端

clipboard.png
ChannelPipeline和ChannelHandlerContext也實現了ChannelInboundInvoker和ChannelOutboundInvoker藉口;Channel接口繼承了ChannelOutboundInvoker接口
即,調用ChannelInboundInvoker接口定義的方法,會觸發ChannelPipeline中下一個ChannelInboundHandler中對應的回調方法;ChannelOutboundInvoker同理bootstrap

【P89 ChannelPipeline】
For each new channel, a new ChannelPipeline is created and attached to the channel. Once attached, the coupling between the channel and the ChannelPipeline is permanent.app

Modifications on the ChannelPipeline can be done on-the-fly, which means you can add/remove/replace ChannelHandler even from within another ChannelHandler or have it remove itself. This allows writing flexible logic, such as multiplexer, but Ill go into more detail later in this chapter.ide

Normally each ChannelHandler that is added to the ChannelPipeline will process the event that is passed through it in the IO-Thread, which means you MUST NOT block as otherwise you block the IO-Thread and so affect the overall handling of IO.
Sometimes its needed to block as you may need to use legancy APIs which only offers a blocking API. For example this is true for JDBC. For exactly this use-case Netty allows to pass a EventExecutorGroup to each of the ChannelPipeline.add* methods. If a custom
EventExecutorGroup is passed in the event will be handled by one oft he EventExecutor contained in this EventExecutorGroup and so moved. A default implementation which is called DefaultEventExecutorGroup comes as part of Netty.oop

【P95 ChannelHandlerContext】
The ChannelHandlerContext never changes for an added ChannelHandler so its safe to get cached.flex

The ChannelHandlerContext does implement ChannelInboundInvoker and ChannelOutboundInvoker. It has many methods that are also present on the Channel or the ChannelPipeline itself. The difference is that if you call them on the Channel or ChannelPipeline they always flow through the complete ChannelPipeline. In contrast, if you call a method on the ChannelHandlerContext, it starts at the current position and notify the closes ChannelHandler in the ChannelPipeline that can handle the event.ui

Now if youd like to have the event flow through the whole ChannelPipeline, there are two different ways of doing so:this

  • Invoke methods on the Channel.
  • Invoke methods on the ChannelPipeline

You should also notice that the Channel and the
ChannelPipeline are accessible via the ChannelHandlerContextspa

Event在ChannelPipeline中的傳輸:
clipboard.png
而對於以下代碼:
clipboard.png
過程是這樣的:
clipboard.png3d

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

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.

【P100 The state model】
Netty has a simple but powerful state model that maps perfectly to the ChannelInboundHandler methods.
即Netty擁有一個簡單且強大的狀態模型,它們對應着ChannelInboundHandler中的方法:
clipboard.png
clipboard.png
【P101 狀態之間的遷移】

【6.4 ChannelHandlers and their types】
Netty uses a well-defined type-hierarchy to represent the different handler types. The parent of all of them is the ChannelHandler. It provides lifecycle operations that are called after a ChannelHandler is added or removed from its ChannelPipeline.
clipboard.png

Netty provides a skeleton implementation for ChannelHandler called ChannelHandlerAdapter. This provides base implementations for all of its methods so you can implement (override) only the methods youre interested in. Basically what it does is forward the event to the next ChannelHandler in the ChannelPipeline until the end is hit.

【6.4.2 Inbound handlers】

  1. ChannelInboundHandler extends ChannelHandler(是接口)
    Every method of ChannelInboundHandler is a counterpart of a method that can be invoked on the ChannelInboundInvoker, which is extended by ChannelHandlerContext and ChannelPipeline.
    Netty provides a skeleton implementation for ChannelInboundHandler implementations called ChannelInboundHandlerAdapter. This provides base implementations for all of its methods and allows you to implement (override) only the methods youre interested in. All of these methods implementations, by default, forward the event to the next ChannelInboundHandler in the ChannelPipeline by calling the same method on the ChannelHandlerContext.
    Important to note is that the ChannelInboundHandler which handles received messages and so @Override the channelRead(…) method is responsible to release resources. This is especially important as Netty uses pooled resources for ByteBuf and so if you forgot to release the resource you will end up with a resource leak. Fortunately Netty will log resources which was missed to be released with WARN loglevel, so it should be quite easy for you to figure out when you missed to do so.
    clipboard.png
    clipboard.png
    As releasing the resources by hand can be cumbersome there is also SimpleChannelInboundHandler, which will take care of it for you. This way you will not need to care about it at all. The only important thing here is to remember that if you use SimpleChannelInboundHandler, it will release the message once it was processed and so you MUST NOT store a reference to it for later usage:
    clipboard.png
    Often you may want to decode bytes to a custom message type, and you may be tempted to implement either ChannelInboundHandler or extend ChannelInboundhandlerAdapter. But hold on a second, theres an even better solution to this problem. Those kinds of functionality are easily implemented using the codec framework, which Ill explain later in the chapter.
    If you use ChannelInboundHandler, ChannelInboundHandlerAdapter or SimpleChannelInboundhandler depends on your needs. Most of the times you use SimpleChannelInboundHandler in the case of handling messages and ChannelInboundHandlerAdapter for other inbound events / state changes.
    【P106 Inbound Message handling and reference counting】
    由於Netty使用引用計數來管理ByteBuf,從而實現ByteBuf池來減小內存的allocation和release,因此使用ChannelInboundHandlerAdapter時,若是channelRead(ctx, msg)所在的Handler是最後一個處理這個msg的Handler(即不會調用ctx.fireChannelRead(msg)),則必須在方法返回以前release這個msg(若是msg實現了ReferenceCounted接口);若是使用的是SimpleChannelInboundhandler,在從channelRead(ctx, msg)返回前(執行後續Handler以後)會自動release這個msg(見源碼,在finally子句中)
  2. ChannelInitializer
    It does exactly what its name states. It allows you to init the Channel once its registered with its EventLoop and ready to process I/O. The ChannelInitializer is mainly used to set up the ChannelPipeline for each Channel that is created. This is done as part of the bootstrapping

【6.4.3 Outbound handlers】

  1. ChannelOutboundHandler
    The ChannelOutboundHandler provides methods that are called when outbound operations are requested. These are the methods listed in the ChannelOutboundInvoker interface thats extended by Channel, ChannelPipeline, and ChannelHandlerContext.
    Allmost all of the methods take a ChannelPromise as an argument that MUST be notified once the request should stop to get forwarded through the ChannelPipeline.
    Netty provides a skeleton implementation for ChannelOutboundHandler implementations called ChannelOutboundHandlerAdapter. This provides base
    implementations for all of its methods and allows you to implement (override) only the methods youre interested in. All these method implementations, by default, forward the event to the next ChannelOutboundHandler in the ChannelPipeline by calling the same method on the ChannelHandlerContext.
    Its important to remember to release resources and notify the ChannelPromise. If the ChannelPromise is not notified it may lead to situations where a ChannelFutureListener is not notified about a handled message. 若是msg已經被當前Handler處理且不須要在ChannelPipeline中繼續傳遞,應該及時release,不然到達ChannelPipeline的最前端(到達Transport)會被自動release
相關文章
相關標籤/搜索