Netty分布式pipeline管道創(chuàng)建方法跟蹤解析
上一章節(jié)回顧:Netty分布式源碼分析監(jiān)聽讀事件
概述
pipeline, 顧名思義, 就是管道的意思, 在netty中, 事件在pipeline中傳輸, 用戶可以中斷事件, 添加自己的事件處理邏輯, 可以直接將事件中斷不再往下傳輸, 同樣可以改變管道的流向, 傳遞其他事件.這里有點類似于Spring的AOP, 但是比AOP實現(xiàn)起來簡單的多
事件通常分為兩種, 一是inBound事件, 另一種是outBound事件, inBound事件, 顧名思義, 就是從另一端流向自己的事件, 比如讀事件, 連接完成事件等等, outBound, 是從自己流向另一端的事件, 比如連接事件, 寫事件, 刷新緩沖區(qū)事件等等
在netty中, 事件是通過handler對象進行處理的, 里面封裝著事件的處理邏輯.而每個handler, 是由HandlerContext進行包裝的, 里面封裝了對事件傳輸?shù)牟僮?/p>
通過之前的學習, 我們知道每一個channel綁定一個pipeline, 那么pipeline和handler又是什么關系呢?
其實pipeline我們可以理解成是一個雙向鏈表的數(shù)據(jù)結構, 只是其中存放的并不是數(shù)據(jù)而是HandlerContext, 而HandlerContext又包裝了handler, 事件傳輸過程中, 從頭結點(或者尾節(jié)點)開始, 找到下一個HandlerContext, 執(zhí)行其Handler的業(yè)務邏輯, 然后再繼續(xù)往下走, 直到執(zhí)行到尾節(jié)點(或者頭結點, 反向)為止, 通過一幅圖了解其大概邏輯:
這里head代表pipeline的頭結點, tail代表pipeline的尾節(jié)點, 這兩個節(jié)點是會隨著pipeline的初始化而創(chuàng)建, 并且不會被刪除
HandlerContext的簡單繼承關系比較簡單, 默認的是DefaultChannelHandlerContext, 繼承于AbstractChannelHandlerContext
而Handler分為InboundHandler和outBoundHandler, Inbound專門處理inbound事件, outBound專門用于處理outBound事件
繼承關系如下圖:
從圖中不難看出, 如果屬于ChannelInboundHandler的子類, 則屬于Inbound類型的handler
如果是ChannelOutboundHandler的子類, 則屬于Outbound類型的handler
了解了其大概邏輯, 我們繼續(xù)跟到源碼中, 看其實如何體現(xiàn)的:
pipeline的創(chuàng)建
回顧之前NioServerSocketChannel的創(chuàng)建過程
我們看AbstractChannel的構造方法:
protected AbstractChannel(Channel parent) { this.parent = parent; id = newId(); unsafe = newUnsafe(); pipeline = newChannelPipeline(); }
我們跟到newChannelPipeline()中:
protected DefaultChannelPipeline newChannelPipeline() { //傳入當前channel return new DefaultChannelPipeline(this); }
我們看到這里創(chuàng)建了一個DefaultChannelPipeline, 并將自身channel傳入
繼續(xù)跟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相關的內(nèi)容, 之后的章節(jié)會講到
首先, 這里初始化了兩個節(jié)點, head節(jié)點和tail節(jié)點, 在pipeline中代表頭結點和尾節(jié)點
我們首先跟到這tail節(jié)點類中,也就是TailContext類:
final class TailContext extends AbstractChannelHandlerContext implements ChannelInboundHandler { TailContext(DefaultChannelPipeline pipeline) { //inbound處理器 super(pipeline, null, TAIL_NAME, true, false); //將當前節(jié)點設置為已添加, head和tail..... setAddComplete(); } //自身也是handler @Override public ChannelHandler handler() { return this; } //方法省略
這個是DefualtPipline的內(nèi)部類, 首先看其繼承了AbstractChannelHandlerContext類, 說明自身是個HandlerContext, 同時也實現(xiàn)ChannelInboundHander接口, 并且其中的handler()方法返回了自身, 說明自身也是handler, 而實現(xiàn)ChannelInboundHander, 說明自身只處理Inbound事件
構造方法中, 調(diào)用了父類的構造器, 看其中參數(shù):
pipeline是自身所屬的pipeline
executor為null
TAIL_NAME是當前handler, 也就是自身的命名
true代表自身是inboundHandler
fasle代表自身不是outboundHandler
繼續(xù)跟到父類構造方法中:
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是線程執(zhí)行器, 這里為空
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節(jié)點, head節(jié)點就不難理解, 同樣繼承了AbstractChannelHandlerContext, 說明自身是一個HandlerContext, 與tail不同的是, 這里實現(xiàn)了ChannelOutboundHandler接口和ChannelOutboundHandler接口, 說明其既能處理inbound事件也能處理outbound的事件, handler方法返歸自身, 說明自身是一個handler
在構造方法中初始化了一個Unsafe類型的成員變量, 是通過自身綁定的channel拿到的, 說明這個類中可以進行對channel的讀寫操作
這里同樣調(diào)用了父類的構造方法, 不同的是, 這里inbound參數(shù)傳入了false, 而outbound參數(shù)傳入了true, 這里說明這里標志的事件是outbound事件
同學們可能疑惑, 為什么同時執(zhí)行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, 繼續(xù)往下看:
head.next = tail;
tail.prev = head;
tail節(jié)點和head節(jié)點中的next和prev屬性, 其實是其父類AbstractChannelHandlerContext, 每一個handlerContext都擁有這兩個屬性, 代表自身的下一個節(jié)點和上一個節(jié)點, 因為我們概述中介紹過pipeline其實是一個雙向鏈表, 所以其中每一個節(jié)點必須有指向其他節(jié)點的指針, 熟悉雙向鏈接數(shù)據(jù)結構的同學應該不會陌生
這里head節(jié)點的next屬性是tail節(jié)點, tail節(jié)點的prev屬性是head, 說明當前雙向鏈表只有兩個節(jié)點, head和tail, 其中head下一個節(jié)點指向tail, tail的上一個節(jié)點指向head, 如圖所示:
以上就是pipeline的初始化過程,更多關于Netty分布式pipeline管道創(chuàng)建的資料請關注腳本之家其它相關文章!
相關文章
詳解Spring Boot 使用Java代碼創(chuàng)建Bean并注冊到Spring中
本篇介紹了Spring Boot 使用Java代碼創(chuàng)建Bean并注冊到Spring中,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2017-02-02解決SpringMVC使用@RequestBody注解報400錯誤的問題
這篇文章主要介紹了解決SpringMVC使用@RequestBody注解報400錯誤的問題,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-09-09