Netty源码分析第4章(pipeline)—->第1节: pipeline的创建

释放双眼,带上耳机,听听看~!

 

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的业务逻辑
, 然后再继续往下走
, 直到执行到尾节点
(或者头结点
, 反向
)为止
, 通过一幅图了解其大概逻辑
:

Netty源码分析第4章(pipeline)---->第1节: pipeline的创建

4-0-1

        这里
head代表
pipeline的头结点
, tail代表
pipeline的尾节点
, 这两个节点是会随着
pipeline的初始化而创建
, 并且不会被删除

        HandlerContext
的简单继承关系比较简单
, 默认的是
DefaultChannelHandlerContext, 继承于
AbstractChannelHandlerContext 

        而
Handler分为
InboundHandler和
outBoundHandler, Inbound专门处理
inbound事件
, outBound专门用于处理
outBound事件

 

        继承关系如下图
:

Netty源码分析第4章(pipeline)---->第1节: pipeline的创建

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, 如图所示
:

Netty源码分析第4章(pipeline)---->第1节: pipeline的创建

4-1-1

以上就是
pipeline的初始化过程

 

上一节: 监听读事件

下一节: handler的添加

 

给TA打赏
共{{data.count}}人
人已打赏
安全技术

详解Node.js API系列 Http模块(2) CNodejs爬虫实现

2021-12-21 16:36:11

安全技术

从零搭建自己的SpringBoot后台框架(二十三)

2022-1-12 12:36:11

个人中心
购物车
优惠劵
今日签到
有新私信 私信列表
搜索