2024-04-04
版权声明:本文为博主付费文章,严禁任何形式的转载和摘抄,维权必究。 本文链接:https://www.skjava.com/mianshi/baodian/detail/1848495028

回答

在 Netty 中 ChannelHandler 是实现业务逻辑的核心位置,我们都是通过自定义的方式来实现特定的业务逻辑。Netty 提供了如下几种方式来自定义 ChannelHandler

  • 实现 ChannelXxxHandler 接口
    • 实现 ChannelInboundHandler 和 ChannelOutboundHandler 接口来自定义我们的业务 ChannelHandler。其中ChannelInboundHandler 接口负责处理入站事件的接口,ChannelOutboundHandler 处理出站事件的接口。
    • 实现接口的方式虽然可行,但是我们需要实现它们所有的方法,而在实际开发过程中,我们一般都只需要实现 channelRead() 或者其余个别方法,没有必要去实现所有方法,所以不推荐使用
  • 继承 ChannelXxxHandlerAdapter 抽象类
    • ChannelInboundHandlerAdapter 和 ChannelOutboundHandlerAdapter 是 Netty 中用于处理入站和出站事件的适配器类,它们分别继承自 ChannelInboundHandler 和 ChannelOutboundHandler 接口,并提供了这些接口中所有方法的默认空实现。通过继承这两个适配器类,我们可以只关注自己感兴趣的方法即可,而不必重写所有方法,从而简化自定义 ChannelHandler 。
  • 继承 SimpleChannelInboundHandler
    • 在绝大多数场景下,我们其实都只需要关注入站事件,只需要处理特定的消息类型。SimpleChannelInboundHandler 是一个入站处理器,它设计的目的是简化入站消息处理的过程,并提供了自动释放消息对象的功能。
    • 简化消息处理逻辑:SimpleChannelInboundHandler 将消息处理的逻辑抽象为channelRead0(),让我们只需要专注于处理特定类型的消息,而不必担心其他的网络通信细节。它内部通过 TypeParameterMatcher 来判断泛型类型是否与给定的参数类型匹配,如果匹配就交由该 ChannelHandler 处理,否则就传递给下一个 ChannelHandler。
    • 自动释放消息对象:SimpleChannelInboundHandler 在处理完消息后,会自动释放消息对象,这是通过 Netty 框架内部的引用计数机制实现的。这一特性非常重要,因为在处理大量消息时,手动释放消息对象可能会容易出错,导致内存泄漏或访问已释放对象的问题。SimpleChannelInboundHandler 保证了消息对象在处理完后被正确释放,让我们不再担心资源的泄露,减轻了我们的负担。
    • 消息适用性:SimpleChannelInboundHandler 只处理特定类型的消息(根据指定的泛型),它会根据消息的类型来选择是否处理消息。如果消息不适用于该处理器,它将将消息传递给下一个适合的处理器。
  • 继承 ChannelDuplexHandler
    • ChannelDuplexHandler 同时继承 ChannelInboundHandlerAdapter 和 ChannelOutboundHandlerAdapter,因此它可以同时作为入站和出站处理器。这对于需要同时处理入站和出站事件的场景非常有用。

详解

我们先看 ChannelHandler 结构图:

使用 ChannelXxxHandler 接口

ChannelInboundHandler 和 ChannelOutboundHandler 都继承自 ChannelHandler 接口,故而我们可以使用ChannelInboundHandler 和 ChannelOutboundHandler 接口来自定义我们的业务 ChannelHandler。

ChannelInboundHandler

ChannelInboundHandler 接口负责处理入站事件的接口。入站事件是从网络中接收数据并传递到应用程序的事件,例如连接建立、数据接收等。主要方法包括:

  • channelRegistered(ChannelHandlerContext ctx): 当Channel已经注册到EventLoop时调用。
  • channelUnregistered(ChannelHandlerContext ctx): 当Channel已经从EventLoop中取消注册时调用。
  • channelActive(ChannelHandlerContext ctx): 当Channel处于活动状态时调用,表示连接已经建立。
  • channelInactive(ChannelHandlerContext ctx): 当Channel处于非活动状态时调用,表示连接已经关闭。
  • channelRead(ChannelHandlerContext ctx, Object msg): 当有入站事件到达时调用,可以在这里处理接收到的数据。
  • channelReadComplete(ChannelHandlerContext ctx): 当前ChannelHandler所属的Channel上的数据读取完成时调用。
  • exceptionCaught(ChannelHandlerContext ctx, Throwable cause): 在处理过程中发生异常时调用。

ChannelOutboundHandler

ChannelOutboundHandler 处理出站事件的接口。出站事件是数据从应用程序流向网络的事件,例如数据发送、连接关闭等。主要方法包括:

  • bind(ChannelHandlerContext ctx, SocketAddress localAddress, ChannelPromise promise): 绑定Channel到指定的本地地址。
  • connect(ChannelHandlerContext ctx, SocketAddress remoteAddress, SocketAddress localAddress, ChannelPromise promise): 连接到远程地址。
  • disconnect(ChannelHandlerContext ctx, ChannelPromise promise): 断开与远程地址的连接。
  • close(ChannelHandlerContext ctx, ChannelPromise promise): 关闭Channel。
  • write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise): 当有出站事件时调用,可以在这里处理要发送的数据。
  • flush(ChannelHandlerContext ctx): 当Channel的数据需要被冲刷到远程节点时调用。
  • exceptionCaught(ChannelHandlerContext ctx, Throwable cause): 在处理过程中发生异常时调用。