1. 程式人生 > >Netty原始碼分析第4章(pipeline)---->第1節: pipeline的建立

Netty原始碼分析第4章(pipeline)---->第1節: pipeline的建立

 

Netty原始碼分析第四章: pipeline

 

概述:

         pipeline, 顧名思義, 就是管道的意思, netty, 事件在pipeline中傳輸, 使用者可以中斷事件, 新增自己的事件處理邏輯, 可以直接將事件中斷不再往下傳輸, 同樣可以改變管道的流向, 傳遞其他事件.這裡有點類似於SpringAOP, 但是比AOP實現起來簡單的多

        事件通常分為兩種, 一是inBound事件, 另一種是outBound事件, inBound

事件, 顧名思義, 就是從另一端流向自己的事件, 比如讀事件, 連線完成事件等等, outBound, 是從自己流向另一端的事件, 比如連線事件, 寫事件, 重新整理緩衝區事件等等

        netty, 事件是通過handler物件進行處理的, 裡面封裝著事件的處理邏輯.而每個handler, 是由HandlerContext進行包裝的, 裡面封裝了對事件傳輸的操作

        通過之前的學習, 我們知道每一個channel繫結一個pipeline, 那麼pipelinehandler

又是什麼關係呢?

        其實pipeline我們可以理解成是一個雙向連結串列的資料結構, 只是其中存放的並不是資料而是HandlerContext, HandlerContext又包裝了handler, 事件傳輸過程中, 從頭結點(或者尾節點)開始, 找到下一個HandlerContext, 執行其Handler的業務邏輯, 然後再繼續往下走, 直到執行到尾節點(或者頭結點, 反向)為止, 通過一幅圖瞭解其大概邏輯:

4-0-1

        這裡head代表pipeline的頭結點, tail

代表pipeline的尾節點, 這兩個節點是會隨著pipeline的初始化而建立, 並且不會被刪除

        HandlerContext的簡單繼承關係比較簡單, 預設的是DefaultChannelHandlerContext, 繼承於AbstractChannelHandlerContext 

        而Handler分為InboundHandleroutBoundHandler, 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

executornull

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是執行緒執行器, 這裡為空

inboundoutbound是事件標誌, 這裡分別是truefalse, 也就是自身屬於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但是標誌的事件不同?

 

其實這兩個地方應用的場景是不同的, 繼承ChannelOutboundHandlerChannelOutboundHandler, 說明其既能處理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節點中的nextprev屬性, 其實是其父類AbstractChannelHandlerContext, 每一個handlerContext都擁有這兩個屬性, 代表自身的下一個節點和上一個節點, 因為我們概述中介紹過pipeline其實是一個雙向連結串列, 所以其中每一個節點必須有指向其他節點的指標, 熟悉雙向連結資料結構的同學應該不會陌生

 

 

這裡head節點的next屬性是tail節點, tail節點的prev屬性是head, 說明當前雙向連結串列只有兩個節點, headtail, 其中head下一個節點指向tail, tail的上一個節點指向head, 如圖所示:

4-1-1

以上就是pipeline的初始化過程