Netty原始碼分析第4章(pipeline)---->第1節: pipeline的建立
Netty原始碼分析第四章: pipeline
概述:
pipeline, 顧名思義, 就是管道的意思, 在netty中, 事件在pipeline中傳輸, 使用者可以中斷事件, 新增自己的事件處理邏輯, 可以直接將事件中斷不再往下傳輸, 同樣可以改變管道的流向, 傳遞其他事件.這裡有點類似於Spring的AOP, 但是比AOP實現起來簡單的多
事件通常分為兩種, 一是inBound事件, 另一種是outBound事件, inBound
在netty中, 事件是通過handler物件進行處理的, 裡面封裝著事件的處理邏輯.而每個handler, 是由HandlerContext進行包裝的, 裡面封裝了對事件傳輸的操作
通過之前的學習, 我們知道每一個channel繫結一個pipeline, 那麼pipeline和handler
其實pipeline我們可以理解成是一個雙向連結串列的資料結構, 只是其中存放的並不是資料而是HandlerContext, 而HandlerContext又包裝了handler, 事件傳輸過程中, 從頭結點(或者尾節點)開始, 找到下一個HandlerContext, 執行其Handler的業務邏輯, 然後再繼續往下走, 直到執行到尾節點(或者頭結點, 反向)為止, 通過一幅圖瞭解其大概邏輯:
4-0-1
這裡head代表pipeline的頭結點, tail
HandlerContext的簡單繼承關係比較簡單, 預設的是DefaultChannelHandlerContext, 繼承於AbstractChannelHandlerContext
而Handler分為InboundHandler和outBoundHandler, Inbound專門處理inbound事件, outBound專門用於處理outBound事件
繼承關係如下圖:
4-0-2
從圖中不難看出, 如果屬於ChannelInboundHandler的子類, 則屬於Inbound型別的handler
如果是ChannelOutboundHandler的子類, 則屬於Outbound型別的handler
瞭解了其大概邏輯, 我們繼續跟到原始碼中, 看其實如何體現的:
第一節: pipeline的建立
回顧之前NioServerSocketChannel的建立過程
我們看AbstractChannel的構造方法:
protected AbstractChannel(Channel parent) {
this.parent = parent;
id = newId();
unsafe = newUnsafe();
pipeline = newChannelPipeline();
}
我們跟到newChannelPipeline()中:
protected DefaultChannelPipeline newChannelPipeline() {
//傳入當前channel
return new DefaultChannelPipeline(this);
}
我們看到這裡建立了一個DefaultChannelPipeline, 並將自身channel傳入
繼續跟DefaultChannelPipeline的構造方法:
protected DefaultChannelPipeline(Channel channel) {
this.channel = ObjectUtil.checkNotNull(channel, "channel");
succeededFuture = new SucceededChannelFuture(channel, null);
voidPromise = new VoidChannelPromise(channel, true);
tail = new TailContext(this);
head = new HeadContext(this);
head.next = tail;
tail.prev = head;
}
首先儲存了當前channel
然後儲存了兩個屬性succeededFuture, voidPromise, 這兩個屬性是Future相關的內容, 之後的章節會講到
首先, 這裡初始化了兩個節點, head節點和tail節點, 在pipeline中代表頭結點和尾節點
我們首先跟到這tail節點類中,也就是TailContext類:
final class TailContext extends AbstractChannelHandlerContext implements ChannelInboundHandler {
TailContext(DefaultChannelPipeline pipeline) {
//inbound處理器
super(pipeline, null, TAIL_NAME, true, false);
//將當前節點設定為已新增, head和tail.....
setAddComplete();
}
//自身也是handler
@Override
public ChannelHandler handler() {
return this;
}
//方法省略
這個是DefualtPipline的內部類, 首先看其繼承了AbstractChannelHandlerContext類, 說明自身是個HandlerContext, 同時也實現ChannelInboundHander介面, 並且其中的handler()方法返回了自身, 說明自身也是handler, 而實現ChannelInboundHander, 說明自身只處理Inbound事件
構造方法中, 呼叫了父類的構造器, 看其中引數:
pipeline是自身所屬的pipeline
executor為null
TAIL_NAME是當前handler, 也就是自身的命名
true代表自身是inboundHandler
fasle代表自身不是outboundHandler
繼續跟到父類構造方法中:
AbstractChannelHandlerContext(DefaultChannelPipeline pipeline, EventExecutor executor, String name,
boolean inbound, boolean outbound) {
//名字
this.name = ObjectUtil.checkNotNull(name, "name");
//pipeline
this.pipeline = pipeline;
//執行緒處理器
this.executor = executor;
//事件標識
this.inbound = inbound;
this.outbound = outbound;
ordered = executor == null || executor instanceof OrderedEventExecutor;
}
這裡初始化了自身父類的幾個屬性
pipeline為自身繫結的pipeline
exeutor是執行緒執行器, 這裡為空
inbound和outbound是事件標誌, 這裡分別是true和false, 也就是自身屬於inboundHnadler而不屬於outboundHandler
回到DefaultChannelPipeline的構造方法:
protected DefaultChannelPipeline(Channel channel) {
this.channel = ObjectUtil.checkNotNull(channel, "channel");
succeededFuture = new SucceededChannelFuture(channel, null);
voidPromise = new VoidChannelPromise(channel, true);
tail = new TailContext(this);
head = new HeadContext(this);
head.next = tail;
tail.prev = head;
}
再看HeadContext類:
final class HeadContext extends AbstractChannelHandlerContext
implements ChannelOutboundHandler, ChannelInboundHandler {
private final Unsafe unsafe;
HeadContext(DefaultChannelPipeline pipeline) {
super(pipeline, null, HEAD_NAME, false, true);
unsafe = pipeline.channel().unsafe();
setAddComplete();
}
@Override
public ChannelHandler handler() {
return this;
}
}
看過了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主要是保證在事件傳輸中保證事件的單方向流動, 在後面事件傳輸我們能領會到
再跟進父類的構造方法, 又是我們熟悉的部分:
AbstractChannelHandlerContext(DefaultChannelPipeline pipeline, EventExecutor executor, String name,
boolean inbound, boolean outbound) {
//名字
this.name = ObjectUtil.checkNotNull(name, "name");
//pipeline
this.pipeline = pipeline;
//執行緒處理器
this.executor = executor;
//事件標識
this.inbound = inbound;
this.outbound = outbound;
ordered = executor == null || executor instanceof OrderedEventExecutor;
}
初始化了pipeline, executor, 和事件標識的屬性
回到DefaultChannelPipeline的構造方法:
protected DefaultChannelPipeline(Channel channel) {
this.channel = ObjectUtil.checkNotNull(channel, "channel");
succeededFuture = new SucceededChannelFuture(channel, null);
voidPromise = new VoidChannelPromise(channel, true);
tail = new TailContext(this);
head = new HeadContext(this);
head.next = tail;
tail.prev = head;
}
我們介紹完了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的初始化過程