Netty:ChannelPipeline

18 篇文章 2 订阅
7 篇文章 0 订阅

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




评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

bdmh

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值