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做了如下一些事情。
- 获取了SimpleChanelInboundHandler泛型标记里面的实际类型,比如String,Integer等。当然这个获取过程涉及到了缓存的过程,不然每次都解析一遍,效率会比较慢,具体实现可以自己看下netty源码。
- 将实际类型与pipeline上一个context传过来的msg的类型进行匹配,如果匹配,则将消息进行转换。
- 如果不匹配,则将消息发给pipeline的下一个context进行处理,调用fireChannelRead方法。
2.如果ChannelInboundHandler不能处理这类消息,如何传递给下一个ChannelInboundHander进行处理
主要是通过ChannelContext的fireChannelRead方法,将消息msg传输到pipeline的下一个ChannelInboundHandler的context中进行处理。
3.处理完毕后,如何对消息占用的内存空间进行释放?
ByteBuf实现了ReferenceCounted接口,netty遵循这谁消费谁释放的原则,当然如果pipeline链中没有自定义handler消费ByteBuf,TailContext会进行消息的释放。
发表评论:
◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。