netty源码之ChannelHandlerContext
- 一、ChannelHandlerContext是什么?
- 二、ChannelHandlerContext的API
- 1、channel()、pipeline()、handler()、alloc()、executor()
- 2、fire类方法
- 3、read()
- 4、write()
- 三、骨架类AbstractChannelHandlerContext
- 1、alloc()方法
- 2、read()方法
- 3、write方法
- 四、实现类HeadContext
- 1、read()方法
- 2、write()方法
- 3、channelActive()方法
- 五、实现类TailContext
- 1、channelRead()方法
- 六、实现类DefaultChannelHandlerContext
一、ChannelHandlerContext是什么?
ChannelHandlerContext代表了ChannelHandler和ChannelPipline之间的关联,每当有一个ChannelHandler添加到ChannelPipline中时,都会创建一个ChannelHandlerContext。主要功能是管理它所关联的ChannelHandler和在同一个ChannelPipline中的其他ChannelHandler之间的交互。
二、ChannelHandlerContext的API
1、channel()、pipeline()、handler()、alloc()、executor()
返回该ChannelHandlerContext绑定的各种组件。
2、fire类方法
触发对pipeline上下一个ChannelInBoundHandler上的对应方法的调用。
3、read()
将数据从Channel读取到第一个入站缓冲区;如果读取成功则触发一个channelRead事件,并在最后一个消息被读取完成后通知ChannelInBoundHandler的channelReadComplete(ctx)方法。
4、write()
通过该ctx写入消息。
三、骨架类AbstractChannelHandlerContext
在AbstractChannelHandlerContext类中实现了ChannelHandlerContext的绝大多数方法逻辑。
1、alloc()方法
通过pipeline获取channel,再获取到对应的ChannelConfig,调用DefaultChannelConfig的getAllocator()方法。
private volatile ByteBufAllocator allocator = ByteBufAllocator.DEFAULT;
ByteBufAllocator DEFAULT = ByteBufUtil.DEFAULT_ALLOCATOR;
可以看到,只有android是默认使用unpooled的,其他均使用pooled。
alloc = PooledByteBufAllocator.DEFAULT;
public static final PooledByteBufAllocator DEFAULT =
new PooledByteBufAllocator(PlatformDependent.directBufferPreferred());
至此,我们看到默认的分配器是PooledByteBufAllocator。
2、read()方法
首先会寻找下一个出站处理器,然后取其线程调用其read方法。其实普通的ctx在read的时候就是做了一个传递,真正有执行逻辑的就是pipeline的最后一个出站处理器,也就是HeadContext。接第四节第1个方法描述。
3、write方法
注意到,在进行基础检验或者发生异常时,调用了ReferenceCountUtil.release(msg)方法进行内存释放。
接下来就如出一辙了,沿着出站处理器往下传递,直到最后一个HeadContext。
4、file类方法fireChannelRead()方法
找到下一个进站处理器,触发对应方法的调用。
四、实现类HeadContext
pipeline中的第一个ctx,既是入站处理器,也是出站处理器。
1、read()方法
调用了unsafe的beginRead方法。
这个unsafe是channel的unsafe。
该方法在AbstractChannel中实现。调用了钩子方法doBeginRead。我们进AbstractNioChannel类继续追踪
最终是给该channel在selector上注册了读事件。
2、write()方法
同样也是调用了unsafe的write方法。
可以看到是把数据写到了出站缓冲区中。
3、channelActive()方法
除了向后传递,还调用了readIfIsAutoRead()方法。
这个方法也很简单,调用了channel的read方法,最终调用了HeadContext的read方法,也就是本节介绍的第1个方法,为该channel注册了读事件。
五、实现类TailContext
pipeline中的最后一个ctx,入站处理器链的最后一个节点。
1、channelRead()方法
看到仅仅是调用了DefaultChannelPipline的onUnhandledInboundMessage()方法。
在这个方法中,只是打印了日志,并对内存进行了释放。这就告诉我们,在我们自定义实现的inBoundHandler中,只要我们调用file方法把msg传递下去,netty已经给我们做好了内存回收,不用担心内存泄露问题。
六、实现类DefaultChannelHandlerContext
可以看到在该类中并没有过多的方法实现,这也就是netty的设计思想,尽量在Abstract类中把该实现的都实现了。