回答
在 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)
: 在处理过程中发生异常时调用。