入站
当某个 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处理,它的一个强大功能是可以按需推迟操作或者事件,这使得可以通过一些复杂的方法来处理请求:
这里需要注意的是这些操作,应该是我们“人为”主动的去操作,比如我们在代码里deregister了channel,我们代码里read到更多的数据,我们flush ,write了数据等等,可以拦截读写操作等