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类型的过程,一样。