Netty源碼分析第4章(pipeline)---->第3節: handler的刪除

 

Netty源碼分析第四章: pipelinehtml

 

第三節: handler的刪除ide

 

 

上一小節咱們學習了添加handler的邏輯操做, 這一小節咱們學習刪除handler的相關邏輯oop

 

若是用戶在業務邏輯中進行ctx.pipeline().remove(this)這樣的寫法, 或者ch.pipeline().remove(new SimpleHandler())這樣的寫法, 則就是對handler進行刪除, 咱們學習過添加handler的邏輯, 因此對handler刪除操做理解起來也會比較容易源碼分析

咱們首先跟到defaultChannelPipeline的remove(handler)的方法中:學習

public final ChannelPipeline remove(ChannelHandler handler) { remove(getContextOrDie(handler)); return this; }

方法體裏有個remove()方法, 傳入一個 getContextOrDie(handler) 參數, 這個 getContextOrDie(handler) , 其實就是根據handler拿到其包裝類HandlerContext對象this

咱們跟到getContextPrDie這個方法中:spa

private AbstractChannelHandlerContext getContextOrDie(ChannelHandler handler) { AbstractChannelHandlerContext ctx = (AbstractChannelHandlerContext) context(handler); //代碼省略
}

這裏仍然會經過context(handler)方法去尋找, 再跟進去:線程

public final ChannelHandlerContext context(ChannelHandler handler) { if (handler == null) { throw new NullPointerException("handler"); } //從頭遍歷節點
    AbstractChannelHandlerContext ctx = head.next; for (;;) { if (ctx == null) { return null; } //找到handler
        if (ctx.handler() == handler) { return ctx; } ctx = ctx.next; } }

這裏咱們看到尋找的方法也很是的簡單, 就是從頭結點開始遍歷, 遍歷到若是其包裝的handler對象是傳入的handler對象, 則返回找到的handlerContext指針

 

回到remove(handler)方法:code

public final ChannelPipeline remove(ChannelHandler handler) { remove(getContextOrDie(handler)); return this; }

繼續跟到remove方法中:

private AbstractChannelHandlerContext remove(final AbstractChannelHandlerContext ctx) { //當前刪除的節點不能是head, 也不能是tail
    assert ctx != head && ctx != tail; synchronized (this) { //執行刪除操做
 remove0(ctx); if (!registered) { callHandlerCallbackLater(ctx, false); return ctx; } //回調刪除handler事件
        EventExecutor executor = ctx.executor(); if (!executor.inEventLoop()) { executor.execute(new Runnable() { @Override public void run() { callHandlerRemoved0(ctx); } }); return ctx; } } callHandlerRemoved0(ctx); return ctx; }

首先要斷言刪除的節點不能是tail和head

而後經過remove0(ctx)進行實際的刪除操做, 跟到remove0(ctx)中:

private static void remove0(AbstractChannelHandlerContext ctx) { //當前節點的前置節點
    AbstractChannelHandlerContext prev = ctx.prev; //當前節點的後置節點
    AbstractChannelHandlerContext next = ctx.next; //前置節點的下一個節點設置爲後置節點
    prev.next = next; //後置節點的上一個節點設置爲前置節點
    next.prev = prev; }

這裏的操做也很是簡單, 作了一個指針移動的操做, 熟悉雙向鏈表的小夥伴應該不會陌生, 刪除節點邏輯大概以下圖所示:

4-3-1

回到remove(ctx)方法:

private AbstractChannelHandlerContext remove(final AbstractChannelHandlerContext ctx) { //當前刪除的節點不能是head, 也不能是tail
    assert ctx != head && ctx != tail; synchronized (this) { //執行刪除操做
 remove0(ctx); if (!registered) { callHandlerCallbackLater(ctx, false); return ctx; } //回調刪除handler事件
        EventExecutor executor = ctx.executor(); if (!executor.inEventLoop()) { executor.execute(new Runnable() { @Override public void run() { callHandlerRemoved0(ctx); } }); return ctx; } } callHandlerRemoved0(ctx); return ctx; }

咱們繼續往下看, 若是當前線程不是eventLoop線程則將回調刪除事件封裝成task放在taskQueue中讓eventLoop線程進行執行, 不然, 則直接執行回調刪除事件

跟到callHandlerRemoved0(ctx)方法中:

private void callHandlerRemoved0(final AbstractChannelHandlerContext ctx) { try { try { //調用handler的handlerRemoved方法
 ctx.handler().handlerRemoved(ctx); } finally { //將當前節點狀態設置爲已移除
 ctx.setRemoved(); } } catch (Throwable t) { fireExceptionCaught(new ChannelPipelineException( ctx.handler().getClass().getName() + ".handlerRemoved() has thrown an exception.", t)); } }

與添加handler的邏輯同樣, 這裏會調用當前handler的handlerRemoved方法, 若是用戶沒有重寫該方法, 則會調用其父類的方法, 方法體在ChannelHandlerAdapter類中有定義, 咱們跟進去

public void handlerRemoved(ChannelHandlerContext ctx) throws Exception { }

同添加handler同樣, 也是一個空實現, 這裏用戶能夠經過重寫來添加本身須要的邏輯

以上就是刪除handler的相關操做

 

上一節: handler的添加

下一節: 傳播inbound事件

相關文章
相關標籤/搜索