DefaultChannelPipeline类在初始化时,会创建两个ChannelHandlerContext实例,一个为head,一个为tail。Head为头部,Tail为尾部。其实给ChannelPipeline添加handler是,都是封装成一个ChannelHandlerContext再添加至channelpipeline, 所以实际上pipeline维护的一个有ChannelHandlerContext的双向链表,头为Head, 尾部为Tail.
Head跟Tail是两个很重要的HandlerContext.
所有出站的操作最后都是通过head来实现具体io操作。head同时实现了inbount与outbound两个接口,所以所有入站操作第一个是到达head,所有出站操作最后一个到达head
@Override
public void bind(
ChannelHandlerContext ctx, SocketAddress localAddress, ChannelPromise promise) throws Exception {
unsafe.bind(localAddress, promise);
}
最后由channel的unsafe内部类执行具体的IO操作(unsafe会使用java nio的api完成操作)。其他的IO操作还有connect,disconnect,close,deregister,read,write,flush。
对于入站操作,head也提供了实现,在往后传event的基础上,不同的event会有一些额外的操作。
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
ctx.fireChannelActive();
readIfIsAutoRead();
}
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
ctx.fireChannelActive();
readIfIsAutoRead();
}
@Override
public void channelInactive(ChannelHandlerContext ctx) throws Exception {
ctx.fireChannelInactive();
}
tail这个ChannelHandlerContext实现了ChannelInboundHandler接口,左右最后一个inboundHandler, 基本上是吞掉所有消息,一些接口会做消息的释放。
@Override
public void channelRegistered(ChannelHandlerContext ctx) throws Exception { }
@Override
public void channelUnregistered(ChannelHandlerContext ctx) throws Exception { }
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
onUnhandledInboundChannelActive();
}
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
onUnhandledInboundMessage(msg);
}
protected void onUnhandledInboundMessage(Object msg) {
try {
logger.debug(
"Discarded inbound message {} that reached at the tail of the pipeline. " +
"Please check your pipeline configuration.", msg);
} finally {
ReferenceCountUtil.release(msg);
}
}
channelpipeline提供了bind,connect,disconnect,close,deregister,flush,write,writeAndFlush等操作,这些操作都是调用tail的对应同名方法(将event传到下一个outboundhandler),最后到达head,head再使用unsafe来执行相应的操作。
@Override
public final ChannelFuture bind(SocketAddress localAddress) {
return tail.bind(localAddress);
}
对于入站操作,channelpipeline都是提供fireXXX的接口,从head开始往后传。
@Override
public final ChannelPipeline fireChannelActive() {
AbstractChannelHandlerContext.invokeChannelActive(head);
return this;
}