Netty:ChannelPipeline

来源:互联网 发布:贵阳行知科技职业学校 编辑:程序博客网 时间:2024/06/05 14:49

ChannelPipeline是一个Handler的集合,它负责处理和拦截inbound或者outbound的事件和操作。他是通过 Intercepting Filter的模式,让用户可以控制Channe各种操作之间的交互。Channel的bind,connect,close等都是通过pipeline进行操作的,摘几段AbstractChannel的代码便能看得出:

@Overridepublic ChannelFuture connect(SocketAddress remoteAddress, SocketAddress localAddress) {return pipeline.connect(remoteAddress, localAddress);}@Overridepublic ChannelFuture disconnect() {return pipeline.disconnect();}@Overridepublic 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 {@Overridepublic void channelRegistered(ChannelHandlerContext ctx)throws Exception {// TODO Auto-generated method stubsuper.channelRegistered(ctx);System.out.println("<<<<<<<<<<<<<<<<<< 01 registered channel >>>>>>>>>>>>>>>>>>");}}//第二个public class ClientHandler02 extends ChannelInboundHandlerAdapter {@Overridepublic void channelRegistered(ChannelHandlerContext ctx)throws Exception {// TODO Auto-generated method stubsuper.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类型的过程,一样。




0 0
原创粉丝点击