Netty:ChannelPipeline

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

时间: 2024-10-08 11:37:12

Netty:ChannelPipeline的相关文章

责任链模式的使用-Netty ChannelPipeline和Mina IoFilterChain分析

本文来自网易云社区 作者:乔安然 1. Chain of Responsiblity 定义: 使多个对象都有机会处理请求,从而避免请求的发送者和接受者之间的耦合关系.将这个对象连成一条链,并沿着这条链传递该请求,直到有一个对象处理他为止. 结构实图: 2. Netty ChannelPipeline 分析 Netty的ChannelPipeline和ChannelHandler机制类似于Servlet和Filter过滤器,这类过滤器其实就是责任链模式的一种变形,方便事件的拦截和用户业务逻辑的定制

在Netty上构建Servlet

众所周知,Netty是一款高性能的I/O框架,那怎么在它之上构建Web服务呢,今天网上搜了一篇文章,学习了一下: Java Servlets have been vastly used in companies for more than 10 years now. Recently another project from JBoss named Netty has gained on popularity to serve data. From Netty website: "Netty h

Netty源码学习——ChannelPipeline模型分析

参考Netty API io.netty.channel.ChannelPipeline A list of ChannelHandlers which handles or intercepts inbound events and outbount operations of aChannel.ChannelPipeline implements an advanced form of theIntercepting Filter pattern to give a user full co

【Netty】ChannelHandler和ChannelPipeline

一.前言 前面学习了Netty的ByteBuf,接着学习ChannelHandler和ChannelPipeline. 二.ChannelHandler和ChannelPipeline 2.1 ChannelHandler 在ChannelPipeline中,ChannelHandler可以被链在一起处理用户逻辑. 1. Channel生命周期 Channel接口定义了一个简单但是强大的状态模型,该模型与ChannelInboundHandler API紧密联系,Channel有如下四种状态.

Netty in Action (十五) 第六章节 第一部分 ChannelHandler和ChannelPipeline

本章内容包括: 1)ChannelHandler和ChannelPipeline的APIs 2)检测内存泄漏 3)异常处理 在之前的一个章节中,我们学习了ByteBuf,Netty的数据容器,在这个章节中,我们将讲解Netty的数据流和对应的处理组件,然后我们将我们已经学过的所有组件整合在一起 你已经知道多个ChannelHandler可以被链式的放入ChannelPipeline来将所有的处理逻辑组织在一起,我们将学习包涵这些有关类的很多用户案例和他们之间的对应关系------ChannelH

Netty 系列四(ChannelHandler 和 ChannelPipeline).

一.概念 先来整体的介绍一下这篇博文要介绍的几个概念(Channel.ChannelHandler.ChannelPipeline.ChannelHandlerContext.ChannelPromise): Channel:Netty 中传入或传出数据的载体:ChannelHandler:Netty 中处理入站和出站数据的应用程序逻辑的容器:ChannelPipeline:ChannelHandler链 的容器:ChannelHandlerContext:代表了 ChannelHandler

netty源码解解析(4.0)-8 ChannelPipeline的设计

io.netty.channel.ChannelPipeline 设计原理 上图中,为了更直观地展示事件处理顺序, 故意有规律地放置两种handler的顺序,实际上ChannelInboundHandler和ChanneOutboundHandler的顺序可以是任意,取决于用户调用add方法把handler方在哪里. ChannelPipeline的特性: 1. 它是一个双向链表 2. 每个节点持有一个ChannelHandler实例,这个实例可以是ChannelInboundHandler类型

Netty中的ChannelPipeline源码分析

ChannelPipeline在Netty中是用来处理请求的责任链,默认实现是DefaultChannelPipeline,其构造方法如下: 1 private final Channel channel; 2 private final ChannelFuture succeededFuture; 3 private final VoidChannelPromise voidPromise; 4 final AbstractChannelHandlerContext head; 5 final

netty的ChannelPipeline执行顺序对inBound和outBound执行器造成的影响

进行这项实验之前,先读了xbmchina的简书文章,感谢这位大神提供的关于channelPipeline和channelHandler文章: [Netty]ChannelPipeline和ChannelHandler(一) [Netty]ChannelHandler的添加和删除(二) [Netty]inBound和outBound事件的传播过程 之前想以leonzm的websocket_demo项目为基础,写netty4版本的聊天室,但是发现netty4的函数不一样,messageReceive