netty最常用两个处理器父类ChannelInboundHandlerAdapter和SimpleChannelInboundHandler区别与使用

我们在使用netty框架的过程中,除了使用内置的处理器外,往往还需要根据自己的设计来实现一些处理器。

通常我们不会直接实现ChannelInboundHandler接口,因为里面涉及到大量方法需要实现,而是继承现有的类,
ChannelInboundHandlerAdapter和SimpleChannelInboundHandler就是我们最常用的两个类,二者实现的功能大致相同,但是在一些细节上还是有差异,需要正确使用,否则会出现一些问题。

ChannelInboundHandlerAdapter

ChannelInboundHandlerAdapter是ChannelInboundHandler一个简单实现,默认情况下不会做任何处理。只是简单的将操作通过fire*方法传到ChannelPipeline中的下一个ChannelHandler中,让链中的下一个ChannelHandler去处理,信息经过channelRead方法处理之后不会自动释放(释放了下个处理器还处理啥)。

   @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        ctx.fireChannelRead(msg);
    }

我们通常会继承此类,覆写上面的channelRead方法,加入自己的逻辑处理。

需要注意的是,覆写方法后,在结尾一定要加上 ctx.fireChannelRead(msg);,否则消息不会继续传递,这是使用时易犯的错误。

SimpleChannelInboundHandler

SimpleChannelInboundHandler则是最常用的被继承类,这个类有个好处是支持泛型,不像ChannelInboundHandler,消息用Object传递,需要做类型强制转换。

    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);
            }

        }

    }

    protected abstract void channelRead0(ChannelHandlerContext var1, I var2) throws Exception;

我们通常只需要覆写channelRead0抽象方法,注意这个方法命名有点怪,本来在日后版本中更名为messageReceived,但netty5被废弃了,只能先用着这有点别扭的名字了。

SimpleChannelInboundHandler实际是继承自上面ChannelInboundHandlerAdapter了,覆写了channelRead方法,并加入了以下特殊处理 ReferenceCountUtil.release(msg),即自动释放消息。

这就形成了另外一个需要注意的点,即如果使用这个类,并且后续的处理器中仍需要读取消息,则必须手工调用
ReferenceCountUtil.retain(msg),也就是让消息的引用计数加1,否则框架对引用计数为0的消息会执行释放和回收。

总结

这两个类功能非常相似,我们应当根据实际情况选择合适的类来继承,覆写相应方法,并注意避免易犯的问题。

ChannelInboundHandlerAdapter需要覆盖的方法是channelRead,不会自动释放消息,需要调用ctx.fireChannelRead(msg)向后续链条处理器传递消息。

SimpleChannelInboundHandler是ChannelInboundHandlerAdapter的子类,做了额外的处理,会自动释放消息,如果还需要继续传递消息,需调用一次ReferenceCountUtil.retain(msg),同时,需注意,同样也需要调用ctx.fireChannelRead(msg)来触发链条中下一处理器处理。

根据以上不同,ChannelInboundHandlerAdapter通常用于处于链条中间的某些环节处理,对数据进行某些处理,如数据验证,需要将消息继续传递。

SimpleChannelInboundHandler则比较适合链条最后一个环节,该环节处理完后,后续不再需要该消息,因此可以自动释放。

虽然我们可以通过附加操作,改变这两个处理器的默认行为,但与其这么做,不如选择合适的处理器,遵循其处理逻辑更合理。

你可能感兴趣的:(netty,netty,处理器,HandlerAdapter,SimpleChannel,实战)