ChannelPipeline是一个Handler的集合,它负责处理和拦截inbound或者outbound的事件和操作。他是通过 Intercepting Filter的模式,让用户可以控制Channe各种操作之间的交互。Channel的bind,connect,close等都是通过pipeline进行操作的,摘几段AbstractChannel的代码便能看得出:
@Override public ChannelFuture connect(SocketAddress remoteAddress, SocketAddress localAddress) { return pipeline.connect(remoteAddress, localAddress); } @Override public ChannelFuture disconnect() { return pipeline.disconnect(); } @Override public ChannelFuture close() { return pipeline.close(); }
ChannelPipeline伴随着Channel的创建二创建,在AbstractChannel的构造函数中:
protected AbstractChannel(Channel parent) { this.parent = parent; id = DefaultChannelId.newInstance(); unsafe = newUnsafe(); pipeline = new DefaultChannelPipeline(this); }
这里创建了DefaultChannelPipeline对象pipeline。
DefaultChannelPipeline继承自ChannelPipeline接口,它通过addLast,addFirst等方法来添加handler,既然有last,有first操作,基本就能确定被添加进去的handler是有顺序的。
没错,DefaultChannelPipeline中维护这一个链表:
final AbstractChannelHandlerContext head; final AbstractChannelHandlerContext tail;
一个头(head),一个尾(tail),继承自AbstractChannelHandlerContext,在DefaultChannelPipeline中,分别由两个内部类创建:
tail = new TailContext(this); head = new HeadContext(this);
初始时,他们互相首尾连接
DefaultChannelPipeline(AbstractChannel channel) { ...... tail = new TailContext(this); head = new HeadContext(this); head.next = tail; tail.prev = head; }
next和prev分别指向对方。TailContext实现的是ChannelInboundHandler接口,HeadContext实现的是ChannelOutboundHandler,一进一出,官方文档对handler的执行顺序是这样说明的:
对于Inbound,是从头head开始依次执行,而对于Outbound,则是从tail向前执行,详见http://netty.io/4.1/api/index.html?io/netty/bootstrap/package-tree.html
看看代码,比如在AbstractChannelHandlerContext的fireChannelRegistered方法中
public ChannelHandlerContext fireChannelRegistered() { AbstractChannelHandlerContext next = findContextInbound(); next.invoker().invokeChannelRegistered(next); return this; }
首先通过findContextInbound去找到Handler上下文
private AbstractChannelHandlerContext findContextInbound() { AbstractChannelHandlerContext ctx = this; do { ctx = ctx.next; } while (!ctx.inbound); return ctx; }
看到了吧,这里有一个while循环,从当前这个上下文对象开始,依次查找它的next指针,因为是查找Inbound,所以只要不是inbound类型,就一直找,对应这个方法的还有一个findContextOutbound方法,是查找outbound类型的。
那么这个this是谁呢?看DefaultChannelPipeline中的fireChannelRegistered
@Override public ChannelPipeline fireChannelRegistered() { head.fireChannelRegistered(); return this; }
代码中通过head的fireChannelRegistered();所以this就是head,即最开始就是从head开始查找。
我们知道,通过addLast可以添加多个handler,那它怎么顺序执行每个handler的方法呢?假如我们声明了两个Inbound的类
//第一个 public class ClientHandler01 extends ChannelInboundHandlerAdapter { @Override public void channelRegistered(ChannelHandlerContext ctx) throws Exception { // TODO Auto-generated method stub super.channelRegistered(ctx); System.out.println("<<<<<<<<<<<<<<<<<< 01 registered channel >>>>>>>>>>>>>>>>>>"); } } //第二个 public class ClientHandler02 extends ChannelInboundHandlerAdapter { @Override public void channelRegistered(ChannelHandlerContext ctx) throws Exception { // TODO Auto-generated method stub super.channelRegistered(ctx); System.out.println("<<<<<<<<<<<<<<<<<< 02 registered channel >>>>>>>>>>>>>>>>>>"); } }
然后初始化时添加
pipeline.addLast("handlerIn1", new ClientHandler01()); pipeline.addLast("handlerIn2", new ClientHandler02());
但我们连接客户端时,会注册Channel,就会触发channelRegistered事件,按照Netty的规则,对于Inbound会先行ClientHandler01,从,ClientHandler01的channelRegistered事件中,调用了super.channelRegistered(ctx);即ChannelInboundHandlerAdapter的方法
@Override public void channelRegistered(ChannelHandlerContext ctx) throws Exception { ctx.fireChannelRegistered(); }
这里又回到AbstractChannelHandlerContext的fireChannelRegistered方法,此时fireChannelRegistered中的this就是传入ctx,就是ClientHandler01对象,所以此时的findContextInbound就会从ClientHandler01开始查找它的next,即查找到ClientHandler02对象,并执行ClientHandler02的registered事件。
对应outbound类型的过程,一样。