Netty源碼分析第四章: pipelinehtml
概述:數據結構
pipeline, 顧名思義, 就是管道的意思, 在netty中, 事件在pipeline中傳輸, 用戶能夠中斷事件, 添加本身的事件處理邏輯, 能夠直接將事件中斷再也不往下傳輸, 一樣能夠改變管道的流向, 傳遞其餘事件.這裏有點相似於Spring的AOP, 可是比AOP實現起來簡單的多ide
事件一般分爲兩種, 一是inBound事件, 另外一種是outBound事件, inBound事件, 顧名思義, 就是從另外一端流向本身的事件, 好比讀事件, 鏈接完成事件等等, outBound, 是從本身流向另外一端的事件, 好比鏈接事件, 寫事件, 刷新緩衝區事件等等源碼分析
在netty中, 事件是經過handler對象進行處理的, 裏面封裝着事件的處理邏輯.而每一個handler, 是由HandlerContext進行包裝的, 裏面封裝了對事件傳輸的操做學習
經過以前的學習, 咱們知道每個channel綁定一個pipeline, 那麼pipeline和handler又是什麼關係呢?this
其實pipeline咱們能夠理解成是一個雙向鏈表的數據結構, 只是其中存放的並非數據而是HandlerContext, 而HandlerContext又包裝了handler, 事件傳輸過程當中, 從頭結點(或者尾節點)開始, 找到下一個HandlerContext, 執行其Handler的業務邏輯, 而後再繼續往下走, 直到執行到尾節點(或者頭結點, 反向)爲止, 經過一幅圖瞭解其大概邏輯:spa
4-0-1線程
這裏head表明pipeline的頭結點, tail表明pipeline的尾節點, 這兩個節點是會隨着pipeline的初始化而建立, 而且不會被刪除3d
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的初始化過程