Handler 对比

Handler 对比

业务常见 handler

类名 说明
IdleStateHandler 空闲检测
FixedLengthFrameDecoder 固定长度的拆包器
MessageToMessageCodec 将编解码操作放到一个类实现
HttpServerCodec http 编解码器
ChunkedWriteHandler 处理大文件传输的情形
HttpObjectAggregator 对 httpMessaHeartBeatHandlerge 进行聚合,聚合成 FullHttpRequest 或 FullHttpResponse
WebSocketServerProtocolHandler 根据 WebSockets 规范的要求,处理 WebSocket 升级握手,PingWebSocketFrames、PongWebSocketFrames 和 CloseWebSocketFrames
TextWebSocketFrameHandler 处理 TextWebSocketFrames 和握手完成事件

ChannelInboundHandlerAdapter

ChannelInboundHandlerAdapterChannelInboundHandler 的一个简单实现,默认情况下不会做任何处理,只是简单的调用 fireChannelRead(msg) 方法传递到 ChannelPipeline 中的下一个 ChannelHandler 去处理。

public class ChannelInboundHandlerAdapter extends ChannelHandlerAdapter implements ChannelInboundHandler {
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        ctx.fireChannelRead(msg);
    }
}

需要注意的是信息经过 channelRead 方法处理之后不会自动释放(因为信息不会被自动释放所以才能将消息传递给下一个 ChannelHandler 处理)。

SimpleChannelInboundHandler

SimpleChannelInboundHandler 支持泛型的消息处理,默认情况下消息处理完将会被自动释放,无法提供 fireChannelRead(msg) 方法传递给 ChannelPipeline 中的下一个 ChannelHandler,如果想要传递给下一个 ChannelHandler 需要调用 ReferenceCountUtil#retain 方法。

SimpleChannelInboundHandler 匹配规则,它会判断消息体类型,如果匹配则调用 channelRead0(ctx, msg) 处理消息,不会向下一个 handler 传递,否则的话调用 ctx.fireChannelRead(msg) 传递数据给下一个 handler。

在客户端,当 channelRead0() 方法完成时,你已经有了传入消息,并且已经处理完它了。当该方法返回时,SimpleChannelInboundHandler 负责释放指向保存该消息的 ByteBuf 的内存引用。 –《Netty In Action》

public abstract class SimpleChannelInboundHandler<I> extends ChannelInboundHandlerAdapter {
    /** 省略一些细节 **/

    public boolean acceptInboundMessage(Object msg) throws Exception {
        return this.matcher.match(msg);
    }

    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        boolean release = true;

        try {
            if (this.acceptInboundMessage(msg)) {
                this.channelRead0(ctx, msg);
            } else {
                release = false;
                ctx.fireChannelRead(msg);
            }
        } finally {
            if (this.autoRelease && release) {
                ReferenceCountUtil.release(msg);
            }

        }

    }
}

ChannelInboundHandlerAdapter vs SimpleChannelInboundHandler

SimpleChannelInboundHandler是有泛型参数的,可以指定一个具体的类型参数,通过 decoder 配合使用,非常方便。ChannelInboundHandlerAdapter 则是直接操作 byte 数组的。

类的关系:

ChannelInboundHandlerAdapter extends ChannelHandlerAdapter implements ChannelInboundHandler

SimpleChannelInboundHandler<I> extends ChannelInboundHandlerAdapter

可以看出 SimpleChannelInboundHandler 是继承 ChannelInboundHandlerAdapter 的,也就是说 SimpleChannelInboundHandler 也拥有 ChannelInboundHandlerAdapter 的方法。

一般而言业务代码 SimpleChannelInboundHandler 写在 channelRead0 方法中,而 ChannelInboundHandlerAdapter 写在 channelRead 方法中,注意后面有 0 后缀区别。

SimpleChannelInboundHandlerchannelRead 的重写:

public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
    boolean release = true;
    try {
        if (acceptInboundMessage(msg)) { //类型匹配
            I imsg = (I) msg;
            channelRead0(ctx, imsg);
        } else {
            release = false;
            ctx.fireChannelRead(msg);
        }
    } finally {
        if (autoRelease && release) {
            ReferenceCountUtil.release(msg); //释放引用
        }
    }
}

SimpleChannelInboundHandlerchannelRead 相比 ChannelInboundHandlerAdapter 而言,主要做了类型匹配以及用完之后释放指向保存该消息的 ByteBuf 的内存引用。

如果说 channelRead 都是同步操作的话,SimpleChannelInboundHandler 是不错的选择,如果操作是异步的话,那他的逻辑就有点麻烦了,例如你把数据交给另外的线程处理了,还没处理就会释放了,这时候 ChannelInboundHandlerAdapter 处理自由的优点也就提现出来了,可以更好的处理更多的特定场景。

SimpleChannelInboundHandler 的好处是可以处理不同的类型对象,并且可以做释放。ChannelInboundHandlerAdapter 的好处则是更自由,在异步的场景下更适合。

参考文章:
从零开始学 netty


  转载请注明: 金点帝国 Handler 对比

 上一篇
nginx gzip 压缩 nginx gzip 压缩
nginx gzip 压缩 本文为个人学习摘要笔记。原文地址:Nginx 优化静态文件访问 Web 开发中需要的静态文件有:CSS、JS、字体、图片,可以通过 web 框架进行访问,但是效率不是最优的。Nginx 对于处理静态文件的效率要
2021-10-18
下一篇 
Handler 执行顺序 Handler 执行顺序
Handler 执行顺序ChannelInboundHandler 和 ChannelOutboundHandlerChannelHandler 有两个子类 ChannelInboundHandler 和 ChannelOutboundHa
2021-10-18
  目录