ChannelHandler

98 阅读2分钟

入站

当某个 ChannelInboundHandler 的实现重写 channelRead()方法时,它将负责显式地 释放与池化的 ByteBuf 实例相关的内存。Netty 为此提供了一个实用方法 ReferenceCountUtil.release() 但是以这种方式管理资源很麻烦,因为我们很容易忽略对于Bytebuf的释放操作。 一种更简单的方式是使用SimpleChannelInboundHandler

public class SimpleDiscardHandler extends SimpleChannelInboundHandler {
@Override 
public void channelRead0(ChannelHandlerContext ctx, Object msg) { 
// No need to do anything special 
 } 
}

这里SimpleChannelInboundHandler会自动释放资源。 如果在代码里复写了ChannelInboundHandlerAdapter的channelRead方法,就必须显示的释放Bytebuf;但由于消息入站是一项常规任务,所以Netty提供了一个特殊的被称为SimpleChannelInboundHandler 的 ChannelInboundHandler 实现。这个实现会在消息被channelRead0()方法消费后自动释放。 当然你也可以调用父类的super.channelRead()方法,将释放操作交给下面的InboundHandler去处理。

出站

在出战方向这边,如果你处理了write()操作,那么代码也必须负责将Bytebuf内存释放。

@Sharable public class DiscardOutboundHandler extends ChannelOutboundHandlerAdapter { 
@Override public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) {
    ReferenceCountUtil.release(msg); 
    promise.setSuccess(); 
  }
}

重要的是,不仅要释放资源,还要通知 ChannelPromise。否则可能会出现 ChannelFutureListener 收不到某个消息已经被处理了的通知的情况。总之,如果一个消息被消费或者丢弃了,并且没有传递给 ChannelPipeline 中的下一个 ChannelOutboundHandler,那么用户就有责任调用 ReferenceCountUtil.release()。如果消息到达了实际的传输层,那么当它被写入时或者 Channel 关闭时,都将被自动释放。

这里还需要着重讲的是ChannnelOutBoundHandler

出站操作和数据将由ChannelOutboundHandler处理,它的一个强大功能是可以按需推迟操作或者事件,这使得可以通过一些复杂的方法来处理请求:

1712931621396.png

这里需要注意的是这些操作,应该是我们“人为”主动的去操作,比如我们在代码里deregister了channel,我们代码里read到更多的数据,我们flush ,write了数据等等,可以拦截读写操作等