Netty源码分析第四章: pipeline
概述
:
pipeline,
顾名思义
, 就是管道的意思
, 在
netty中
, 事件在
pipeline中传输
, 用户可以中断事件
, 添加自己的事件处理逻辑
, 可以直接将事件中断不再往下传输
, 同样可以改变管道的流向
, 传递其他事件
.这里有点类似于
Spring的
AOP, 但是比
AOP实现起来简单的多
事件通常分为两种
, 一是
inBound事件
, 另一种是
outBound事件
, inBound事件
, 顾名思义
, 就是从另一端流向自己的事件
, 比如读事件
, 连接完成事件等等
, outBound, 是从自己流向另一端的事件
, 比如连接事件
, 写事件
, 刷新缓冲区事件等等
在
netty中
, 事件是通过
handler对象进行处理的
, 里面封装着事件的处理逻辑
.而每个
handler, 是由
HandlerContext进行包装的
, 里面封装了对事件传输的操作
通过之前的学习
, 我们知道每一个
channel绑定一个
pipeline, 那么
pipeline和
handler又是什么关系呢
?
其实
pipeline我们可以理解成是一个双向链表的数据结构
, 只是其中存放的并不是数据而是
HandlerContext, 而
HandlerContext又包装了
handler, 事件传输过程中
, 从头结点
(或者尾节点
)开始
, 找到下一个
HandlerContext, 执行其
Handler的业务逻辑
, 然后再继续往下走
, 直到执行到尾节点
(或者头结点
, 反向
)为止
, 通过一幅图了解其大概逻辑
:
4-0-1
这里
head代表
pipeline的头结点
, tail代表
pipeline的尾节点
, 这两个节点是会随着
pipeline的初始化而创建
, 并且不会被删除
HandlerContext
的简单继承关系比较简单
, 默认的是
DefaultChannelHandlerContext, 继承于
AbstractChannelHandlerContext
而
Handler分为
InboundHandler和
outBoundHandler, Inbound专门处理
inbound事件
, outBound专门用于处理
outBound事件
继承关系如下图
:
4-0-2
从图中不难看出
, 如果属于
ChannelInboundHandler的子类
, 则属于
Inbound类型的
handler
如果是
ChannelOutboundHandler的子类
, 则属于
Outbound类型的
handler
了解了其大概逻辑
, 我们继续跟到源码中
, 看其实如何体现的
:
第一节: pipeline的创建
回顾之前
NioServerSocketChannel的创建过程
我们看
AbstractChannel的构造方法
:
1
2
3
4
5
6
7 1protected AbstractChannel(Channel parent) {
2 this.parent = parent;
3 id = newId();
4 unsafe = newUnsafe();
5 pipeline = newChannelPipeline();
6}
7
我们跟到
newChannelPipeline()中
:
1
2
3
4
5 1protected DefaultChannelPipeline newChannelPipeline() {
2 //传入当前channel
3 return new DefaultChannelPipeline(this);
4}
5
我们看到这里创建了一个
DefaultChannelPipeline, 并将自身
channel传入
继续跟
DefaultChannelPipeline的构造方法
:
1
2
3
4
5
6
7
8
9
10 1protected DefaultChannelPipeline(Channel channel) {
2 this.channel = ObjectUtil.checkNotNull(channel, "channel");
3 succeededFuture = new SucceededChannelFuture(channel, null);
4 voidPromise = new VoidChannelPromise(channel, true);
5 tail = new TailContext(this);
6 head = new HeadContext(this);
7 head.next = tail;
8 tail.prev = head;
9}
10
首先保存了当前
channel
然后保存了两个属性
succeededFuture, voidPromise, 这两个属性是
Future相关的内容
, 之后的章节会讲到
首先
, 这里初始化了两个节点
, head节点和
tail节点
, 在
pipeline中代表头结点和尾节点
我们首先跟到这
tail节点类中,也就是TailContext类
:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 1final class TailContext extends AbstractChannelHandlerContext implements ChannelInboundHandler {
2 TailContext(DefaultChannelPipeline pipeline) {
3 //inbound处理器
4 super(pipeline, null, TAIL_NAME, true, false);
5 //将当前节点设置为已添加, head和tail.....
6 setAddComplete();
7 }
8
9 //自身也是handler
10 @Override
11 public ChannelHandler handler() {
12 return this;
13 }
14
15 //方法省略
16
这个是
DefualtPipline的内部类
, 首先看其继承了
AbstractChannelHandlerContext类
, 说明自身是个
HandlerContext, 同时也实现
ChannelInboundHander接口
, 并且其中的
handler()方法返回了自身
, 说明自身也是
handler, 而实现
ChannelInboundHander, 说明自身只处理
Inbound事件
构造方法中
, 调用了父类的构造器
, 看其中参数
:
pipeline
是自身所属的
pipeline
executor
为
null
TAIL_NAME
是当前
handler, 也就是自身的命名
true
代表自身是
inboundHandler
fasle
代表自身不是
outboundHandler
继续跟到父类构造方法中
:
1
2
3
4
5
6
7
8
9
10
11
12
13
14 1AbstractChannelHandlerContext(DefaultChannelPipeline pipeline, EventExecutor executor, String name,
2 boolean inbound, boolean outbound) {
3 //名字
4 this.name = ObjectUtil.checkNotNull(name, "name");
5 //pipeline
6 this.pipeline = pipeline;
7 //线程处理器
8 this.executor = executor;
9 //事件标识
10 this.inbound = inbound;
11 this.outbound = outbound;
12 ordered = executor == null || executor instanceof OrderedEventExecutor;
13}
14
这里初始化了自身父类的几个属性
pipeline
为自身绑定的
pipeline
exeutor
是线程执行器
, 这里为空
inbound
和
outbound是事件标志
, 这里分别是
true和
false, 也就是自身属于
inboundHnadler而不属于
outboundHandler
回到
DefaultChannelPipeline的构造方法
:
1
2
3
4
5
6
7
8
9
10 1protected DefaultChannelPipeline(Channel channel) {
2 this.channel = ObjectUtil.checkNotNull(channel, "channel");
3 succeededFuture = new SucceededChannelFuture(channel, null);
4 voidPromise = new VoidChannelPromise(channel, true);
5 tail = new TailContext(this);
6 head = new HeadContext(this);
7 head.next = tail;
8 tail.prev = head;
9}
10
再看
HeadContext类
:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 1final class HeadContext extends AbstractChannelHandlerContext
2 implements ChannelOutboundHandler, ChannelInboundHandler {
3
4 private final Unsafe unsafe;
5
6 HeadContext(DefaultChannelPipeline pipeline) {
7 super(pipeline, null, HEAD_NAME, false, true);
8 unsafe = pipeline.channel().unsafe();
9 setAddComplete();
10 }
11
12 @Override
13 public ChannelHandler handler() {
14 return this;
15 }
16}
17
看过了
tail节点
, head节点就不难理解
, 同样继承了
AbstractChannelHandlerContext, 说明自身是一个
HandlerContext, 与
tail不同的是
, 这里实现了
ChannelOutboundHandler接口和
ChannelOutboundHandler接口
, 说明其既能处理
inbound事件也能处理
outbound的事件
, handler方法返归自身
, 说明自身是一个
handler
在构造方法中初始化了一个
Unsafe类型的成员变量
, 是通过自身绑定的
channel拿到的
, 说明这个类中可以进行对
channel的读写操作
这里同样调用了父类的构造方法
, 不同的是
, 这里
inbound参数传入了
false, 而
outbound参数传入了
true, 这里说明这里标志的事件是
outbound事件
同学们可能疑惑
, 为什么同时执行
ChannelOutboundHandler接口和
ChannelOutboundHandler但是标志的事件不同
?
其实这两个地方应用的场景是不同的
, 继承
ChannelOutboundHandler和
ChannelOutboundHandler, 说明其既能处理
inbound事件也能处理
outBound的事件
, 但是只有
outbound属性为
true说明自身是一个
outboundhandler, 是一个可以处理
inbound事件的
outboundhandler(估计被绕晕了
), 这两种
handler主要是保证在事件传输中保证事件的单方向流动
, 在后面事件传输我们能领会到
再跟进父类的构造方法
, 又是我们熟悉的部分
:
1
2
3
4
5
6
7
8
9
10
11
12
13
14 1AbstractChannelHandlerContext(DefaultChannelPipeline pipeline, EventExecutor executor, String name,
2 boolean inbound, boolean outbound) {
3 //名字
4 this.name = ObjectUtil.checkNotNull(name, "name");
5 //pipeline
6 this.pipeline = pipeline;
7 //线程处理器
8 this.executor = executor;
9 //事件标识
10 this.inbound = inbound;
11 this.outbound = outbound;
12 ordered = executor == null || executor instanceof OrderedEventExecutor;
13}
14
初始化了
pipeline, executor, 和事件标识的属性
回到
DefaultChannelPipeline的构造方法
:
1
2
3
4
5
6
7
8
9
10 1protected DefaultChannelPipeline(Channel channel) {
2 this.channel = ObjectUtil.checkNotNull(channel, "channel");
3 succeededFuture = new SucceededChannelFuture(channel, null);
4 voidPromise = new VoidChannelPromise(channel, true);
5 tail = new TailContext(this);
6 head = new HeadContext(this);
7 head.next = tail;
8 tail.prev = head;
9}
10
我们介绍完了
head, 和
tail这两个
context, 继续往下看
:
head.next = tail;
tail.prev = head;
tail
节点和
head节点中的
next和
prev属性
, 其实是其父类
AbstractChannelHandlerContext, 每一个
handlerContext都拥有这两个属性
, 代表自身的下一个节点和上一个节点
, 因为我们概述中介绍过
pipeline其实是一个双向链表
, 所以其中每一个节点必须有指向其他节点的指针
, 熟悉双向链接数据结构的同学应该不会陌生
这里
head节点的
next属性是
tail节点
, tail节点的
prev属性是
head, 说明当前双向链表只有两个节点
, head和
tail, 其中
head下一个节点指向
tail, tail的上一个节点指向
head, 如图所示
:
4-1-1
以上就是
pipeline的初始化过程
上一节: 监听读事件
下一节: handler的添加