Netty分布式pipeline管道Handler的刪除邏輯操作
上一小節(jié)我們學(xué)習(xí)了添加handler的邏輯操作, 這一小節(jié)我們學(xué)習(xí)刪除handler的相關(guān)邏輯
刪除handler操作
如果用戶在業(yè)務(wù)邏輯中進(jìn)行ctx.pipeline().remove(this)這樣的寫法, 或者ch.pipeline().remove(new SimpleHandler())這樣的寫法, 則就是對(duì)handler進(jìn)行刪除, 我們學(xué)習(xí)過(guò)添加handler的邏輯, 所以對(duì)handler刪除操作理解起來(lái)也會(huì)比較容易
我們首先跟到defaultChannelPipeline的remove(handler)的方法中:
public final ChannelPipeline remove(ChannelHandler handler) { remove(getContextOrDie(handler)); return this; }
方法體里有個(gè)remove()方法, 傳入一個(gè) getContextOrDie(handler) 參數(shù), 這個(gè) getContextOrDie(handler) , 其實(shí)就是根據(jù)handler拿到其包裝類HandlerContext對(duì)象
我們跟到getContextPrDie這個(gè)方法中
private AbstractChannelHandlerContext getContextOrDie(ChannelHandler handler) { AbstractChannelHandlerContext ctx = (AbstractChannelHandlerContext) context(handler); //代碼省略 }
這里仍然會(huì)通過(guò)context(handler)方法去尋找, 再跟進(jìn)去:
public final ChannelHandlerContext context(ChannelHandler handler) { if (handler == null) { throw new NullPointerException("handler"); } //從頭遍歷節(jié)點(diǎn) AbstractChannelHandlerContext ctx = head.next; for (;;) { if (ctx == null) { return null; } //找到handler if (ctx.handler() == handler) { return ctx; } ctx = ctx.next; } }
這里我們看到尋找的方法也非常的簡(jiǎn)單, 就是從頭結(jié)點(diǎn)開始遍歷, 遍歷到如果其包裝的handler對(duì)象是傳入的handler對(duì)象, 則返回找到的handlerContext
回到remove(handler)方法:
public final ChannelPipeline remove(ChannelHandler handler) { remove(getContextOrDie(handler)); return this; }
繼續(xù)跟到remove方法中:
private AbstractChannelHandlerContext remove(final AbstractChannelHandlerContext ctx) { //當(dāng)前刪除的節(jié)點(diǎn)不能是head, 也不能是tail assert ctx != head && ctx != tail; synchronized (this) { //執(zhí)行刪除操作 remove0(ctx); if (!registered) { callHandlerCallbackLater(ctx, false); return ctx; } //回調(diào)刪除handler事件 EventExecutor executor = ctx.executor(); if (!executor.inEventLoop()) { executor.execute(new Runnable() { @Override public void run() { callHandlerRemoved0(ctx); } }); return ctx; } } callHandlerRemoved0(ctx); return ctx; }
首先要斷言刪除的節(jié)點(diǎn)不能是tail和head
然后通過(guò)remove0(ctx)進(jìn)行實(shí)際的刪除操作, 跟到remove0(ctx)中:
private static void remove0(AbstractChannelHandlerContext ctx) { //當(dāng)前節(jié)點(diǎn)的前置節(jié)點(diǎn) AbstractChannelHandlerContext prev = ctx.prev; //當(dāng)前節(jié)點(diǎn)的后置節(jié)點(diǎn) AbstractChannelHandlerContext next = ctx.next; //前置節(jié)點(diǎn)的下一個(gè)節(jié)點(diǎn)設(shè)置為后置節(jié)點(diǎn) prev.next = next; //后置節(jié)點(diǎn)的上一個(gè)節(jié)點(diǎn)設(shè)置為前置節(jié)點(diǎn) next.prev = prev; }
這里的操作也非常簡(jiǎn)單, 做了一個(gè)指針移動(dòng)的操作, 熟悉雙向鏈表的小伙伴應(yīng)該不會(huì)陌生, 刪除節(jié)點(diǎn)邏輯大概如下圖所示:
回到remove(ctx)方法
private AbstractChannelHandlerContext remove(final AbstractChannelHandlerContext ctx) { //當(dāng)前刪除的節(jié)點(diǎn)不能是head, 也不能是tail assert ctx != head && ctx != tail; synchronized (this) { //執(zhí)行刪除操作 remove0(ctx); if (!registered) { callHandlerCallbackLater(ctx, false); return ctx; } //回調(diào)刪除handler事件 EventExecutor executor = ctx.executor(); if (!executor.inEventLoop()) { executor.execute(new Runnable() { @Override public void run() { callHandlerRemoved0(ctx); } }); return ctx; } } callHandlerRemoved0(ctx); return ctx; }
我們繼續(xù)往下看, 如果當(dāng)前線程不是eventLoop線程則將回調(diào)刪除事件封裝成task放在taskQueue中讓eventLoop線程進(jìn)行執(zhí)行, 否則, 則直接執(zhí)行回調(diào)刪除事件
跟到callHandlerRemoved0(ctx)方法中:
private void callHandlerRemoved0(final AbstractChannelHandlerContext ctx) { try { try { //調(diào)用handler的handlerRemoved方法 ctx.handler().handlerRemoved(ctx); } finally { //將當(dāng)前節(jié)點(diǎn)狀態(tài)設(shè)置為已移除 ctx.setRemoved(); } } catch (Throwable t) { fireExceptionCaught(new ChannelPipelineException( ctx.handler().getClass().getName() + ".handlerRemoved() has thrown an exception.", t)); } }
與添加handler的邏輯一樣, 這里會(huì)調(diào)用當(dāng)前handler的handlerRemoved方法, 如果用戶沒(méi)有重寫該方法, 則會(huì)調(diào)用其父類的方法, 方法體在ChannelHandlerAdapter類中有定義, 我們跟進(jìn)去
public void handlerRemoved(ChannelHandlerContext ctx) throws Exception { }
同添加handler一樣, 也是一個(gè)空實(shí)現(xiàn), 這里用戶可以通過(guò)重寫來(lái)添加自己需要的邏輯
以上就是刪除handler的相關(guān)操作,更多關(guān)于Netty分布式pipeline管道刪除Handler的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Springboot啟動(dòng)執(zhí)行特定代碼的方式匯總
這篇文章主要介紹了Springboot啟動(dòng)執(zhí)行特定代碼的幾種方式,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2021-12-12OpenFeign實(shí)現(xiàn)攜帶請(qǐng)求頭方案詳細(xì)介紹
這篇文章主要介紹了OpenFeign實(shí)現(xiàn)攜帶請(qǐng)求頭方案,在通過(guò)???OpenFeign???進(jìn)行服務(wù)調(diào)用的過(guò)程中,我們需要將用戶的??user-token???、??lang??等信息放入請(qǐng)求header中。在分布式系統(tǒng)中,往往一個(gè)業(yè)務(wù)接口內(nèi)部會(huì)發(fā)生多次RPC調(diào)用2022-11-11springboot動(dòng)態(tài)定時(shí)任務(wù)的實(shí)現(xiàn)方法示例
這篇文章主要給大家介紹了關(guān)于springboot動(dòng)態(tài)定時(shí)任務(wù)的實(shí)現(xiàn)方法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2021-02-02Spring Cloud 覆寫遠(yuǎn)端的配置屬性實(shí)例詳解
這篇文章主要介紹了Spring Cloud 覆寫遠(yuǎn)端的配置屬性的相關(guān)知識(shí),非常不錯(cuò),具有參考借鑒價(jià)值,需要的朋友可以參考下2018-01-01Netty框架實(shí)現(xiàn)TCP/IP通信的完美過(guò)程
這篇文章主要介紹了Netty框架實(shí)現(xiàn)TCP/IP通信,這里使用的是Springboot+Netty框架,使用maven搭建項(xiàng)目,需要的朋友可以參考下2021-07-07SpringBoot中如何對(duì)actuator進(jìn)行關(guān)閉
這篇文章主要介紹了SpringBoot中如何對(duì)actuator進(jìn)行關(guān)閉問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-03-03