SimpleChannelInboundHandler解析

SimpleChannelInboundHandler

在开发netty程序时,往往在netty的传输链条pipeline中加入自定义解码器后,此时消息经过解码器后是以自定义类型出现的,比如String、Integer等等,处于解码器后面的ChannelInboundHandler会接收到这个消息并进行处理。

那么这里就有几个疑问?

1.处于pipleline中的ChannelInboundHandler如何适配到这个自定义类型?

2.如果ChannelInboundHandler不能处理这类消息,如何传递给下一个ChannelInboundHander进行处理

3.处理完毕后,如何对消息占用的内存空间进行释放?

下面就上面三个问题,根据源码进行解读。

1.处于pipleline中的ChannelInboundHandler如何适配到这个自定义类型?

我们知道netty在读取消息时,是分几个阶段的

Channel注册的NioEventLoop循环读取selector监听Channel的事件

获取read事件后,Netty分配ByteBuf,并从Channel中读取数据到ByteBuf中

Channel绑定的pipeline调用fireChannelRead方法,将消息沿着HeadContext传输到TailContext,HeadContext和TailContext中有很多ChannelInboundHandler对应的Context。

整个过程如下:
在这里插入图片描述

那么netty中是如何做到适配这个动作的呢?

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        boolean release = true;
        try {
            if (acceptInboundMessage(msg)) {    1.消息是否匹配
                @SuppressWarnings("unchecked")
                I imsg = (I) msg;				
                channelRead0(ctx, imsg);		2.调用子类的channelRead0方法,imsg已转型
            } else {
                release = false;
                ctx.fireChannelRead(msg); 3.如果不匹配,将消息发送给pipeline下一个handler
            }
        } finally {
            if (autoRelease && release) {
                ReferenceCountUtil.release(msg);4.释放消息
            }
        }
    }

重点看消息的匹配过程,也就是acceptInboundMessage(msg)方法。

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

可以看到有一个macher对象调用了match方法判断msg是否是自己能够处理的消息。

进一步查看matcher的初始化过程

protected SimpleChannelInboundHandler(boolean autoRelease) {    
matcher = TypeParameterMatcher.find(this, SimpleChannelInboundHandler.class, "I");    this.autoRelease = autoRelease;
}

简单来说,TypeParameterMatcher做了如下一些事情。

  1. 获取了SimpleChanelInboundHandler泛型标记里面的实际类型,比如String,Integer等。当然这个获取过程涉及到了缓存的过程,不然每次都解析一遍,效率会比较慢,具体实现可以自己看下netty源码。
  2. 将实际类型与pipeline上一个context传过来的msg的类型进行匹配,如果匹配,则将消息进行转换。
  3. 如果不匹配,则将消息发给pipeline的下一个context进行处理,调用fireChannelRead方法。

2.如果ChannelInboundHandler不能处理这类消息,如何传递给下一个ChannelInboundHander进行处理

主要是通过ChannelContext的fireChannelRead方法,将消息msg传输到pipeline的下一个ChannelInboundHandler的context中进行处理。

3.处理完毕后,如何对消息占用的内存空间进行释放?

ByteBuf实现了ReferenceCounted接口,netty遵循这谁消费谁释放的原则,当然如果pipeline链中没有自定义handler消费ByteBuf,TailContext会进行消息的释放。

发表评论:

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。

微信扫一扫

微信扫一扫

微信扫一扫,分享到朋友圈

SimpleChannelInboundHandler解析