3.5 编码器,解码器和域逻辑:Handler的详细介绍
如前所述,有许多不同类型的处理程序。每个人的工作取决于他们从哪个基类继承。 Netty提供了一系列Adapter类,这使事情变得容易一些。这样做是因为在管道中,每个处理程序负责将Netty事件转发到ChannelPipeline中的下一个处理程序。使用Adapter类(和子类),它会自动为您完成,因此您只需要覆盖您感兴趣的方法/事件。除了Adapter类外,还有其他扩展类,并提供了额外的功能,例如帮助轻松编码/解码消息的功能。
Adapter classes
这里有一些适配器类,使您可以轻松地编写ChannelHandlers。每当您想编写自己的ChannelHandler时,建议您扩展一个适配器类或一个编码器/解码器类(实际上是扩展一个适配器类)。 Netty随附以下适配器:
ChannelHandlerAdapter
ChannelInboundHandlerAdapter
ChannelOutboundHandlerAdapter
ChannelDuplexHandlerAdapter
我们要特别研究的三个ChannelHandler是编码器,解码器和SimpleChannelInboundHandler(这是ChannelInboundHandlerAdapter的子类)
3.5.1 Encoders, decoders
使用Netty发送或接收消息时,必须将其从一种形式转换为另一种形式。如果接收到该消息,则必须将其从字节转换为Java对象(由某种解码器解码)。如果正在发送消息,则必须将其从Java对象转换为字节(由某种类型的编码器编码)。当通过网络,字节消息或消息字节发送数据时,这种转换将始终发生,因为您只能在网络上传输字节。
编码器和解码器有多种类型的基类,具体取决于您要执行的操作。例如,您的应用程序使用Netty的方式不需要立即将消息转换为字节,因此可以将消息转换为另一种消息。仍然使用编码器,但是为此使用了不同的基类。为了弄清楚哪个基类是适用的,有一点约定可以用来知道基类的名称。通常,基类的名称类似于ByteToMessageDecoder或MessageToByteEncoder。或者,如果是特殊类型,您可能会找到ProtobufEncoder和ProtobufDecoder之类的东西,用于支持Google的协议缓冲区。
严格说来,其他处理程序可以完成编码器和解码器的工作,但是请回想一下,我们说过有不同的适配器类,具体取决于您想做什么?对于解码器,有一个ChannelInboundHandlerAdapter或ChannelInboundHandler,所有解码器都可以扩展或实现。channelRead方法/事件被覆盖,从入站通道读取的每个消息均调用此方法。然后,重写的channelRead方法将调用每个解码器的解码方法,并将已解码的消息通过ChannelHandlerContext转发到ChannelPipeline中的下一个ChannelInboundHandler。fireChannelRead(decodedMessage)方法。发送消息时发生类似的事情,除了编码器将消息转换为字节,然后将这些字节转发到下一个ChannelOutboundHandler。
3.5.2 Domain logic
您的应用程序必须处理的最常见的处理程序是接收已解码消息并允许您的应用程序将某些域逻辑应用于消息的处理程序。要创建这样的处理程序,您的应用程序只需扩展名为SimpleChannelInboundHandler的基类,其中T是您的处理程序可以处理的消息类型。在此处理程序中,您的应用程序通过重写基类中的方法之一来获取对ChannelHandlerContext的引用。它们都接受ChannelHandlerContext作为参数,然后可以将其存储为类中的字段。
该处理程序的主要关注方法是channelRead0(ChannelHandlerContext,T)方法。每当Netty调用此方法时,对象T就是消息,您的应用程序随后可以处理该消息。您如何处理消息完全取决于您和应用程序的需求。处理消息时要注意的一件事是,即使Netty中通常有多个线程处理IO,您的应用程序应尽量不要阻塞IO线程,因为这可能会在某些较高的整个环境中导致性能问题。
Blocking operations
你必须完全禁止阻塞IO线程。这意味着在ChannelHandler中执行阻塞操作是有问题的。幸运的是,有一个解决方案。 Netty允许在将ChannelHandlers添加到ChannelPipeline时指定EventExecutorGroup。然后,将使用EventExecutorGroup获得一个EventExecutor,并且此EventExecutor将执行ChannelHandler的所有方法。这里的EventExecutor将使用与用于IO的线程不同的线程,从而释放EventLoop。
最后更新于
这有帮助吗?