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