首頁 > 軟體

Netty分散式pipeline管道Handler的刪除邏輯操作

2022-03-28 13:01:19

上一小節我們學習了新增handler的邏輯操作, 這一小節我們學習刪除handler的相關邏輯

刪除handler操作

如果使用者在業務邏輯中進行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物件

我們跟到getContextPrDie這個方法中

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)方法:

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;
}

這裡的操作也非常簡單, 做了一個指標移動的操作, 熟悉雙向連結串列的小夥伴應該不會陌生, 刪除節點邏輯大概如下圖所示:

回到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的相關操作,更多關於Netty分散式pipeline管道刪除Handler的資料請關注it145.com其它相關文章!


IT145.com E-mail:sddin#qq.com