Netty原始碼分析(七):初識ChannelPipeline

貳級天災發表於2019-05-12

ChannelPipeline單看名稱就可以知道Channel的管道。本篇將結合它的預設實現類DefaultChannelPipeline來對它做一個簡單的介紹。

示例圖

Netty原始碼分析(七):初識ChannelPipeline
上圖是官方提供的ChannelPipeline的事例圖。IO請求經由ChannelOutboundHandlerChannelOutboundHandler處理之後寫出到服務端,服務接收到讀入後,由ChannelInboundHandler依次處理。 下面來看下DefaultChannelPipeline的類圖:
Netty原始碼分析(七):初識ChannelPipeline
DefaultChannelPipeline實現了ChannelPipeline介面,而ChannelPipeline又繼承了ChannelInboundInvokerChannelOutboundInvokerIterableChannelInboundInvoker:發起對ChannelPipeline中下一個ChannelInboundHandler的方法的呼叫。 ChannelOutboundInvoker:發起對ChannelPipeline中下一個ChannelOutboundHandler的方法的呼叫。 Iterable:可遍歷ChannelPipeline中的ChannelHandlerNioEventLoop繼承自SingleThreadEventLoop,而SingleThreadEventLoop又繼承自SingleThreadEventExecutorSingleThreadEventExecutor內部持有一個Thread物件,是Netty多執行緒的基礎。 可以認為, 一個NioEventLoop與一個特定的執行緒進行了繫結,並且在其生命週期內,繫結的執行緒都不會再改變。

DefaultChannelPipeline

DefaultChannelPipeline的主要工作就是對ChannelHandler的管理,包括ChannelHandler的增減,事件的觸發等。

ChannelHandler的增減

addFirst方法為例:

    public final ChannelPipeline addFirst(EventExecutorGroup group, String name, ChannelHandler handler) {
        final AbstractChannelHandlerContext newCtx;
        synchronized (this) {
            // 檢查handler是否可以共享
            checkMultiplicity(handler);
            // 給AbstractChannelHandlerContext起個獨立的名字
            name = filterName(name, handler);
            // 建立DefaultChannelHandlerContext
            newCtx = newContext(group, name, handler);
            // 執行實際的新增操作
            addFirst0(newCtx);
            // channel尚未註冊到eventloop
            if (!registered) {
                // 設定newCtx的狀態為ADD_PENDING
                newCtx.setAddPending();
                // 設定過一會回撥ChannelHandler的handlerAdded方法
                callHandlerCallbackLater(newCtx, true);
                return this;
            }
            EventExecutor executor = newCtx.executor();
            if (!executor.inEventLoop()) {
                newCtx.setAddPending();
                executor.execute(new Runnable() {
                    @Override
                    public void run() {
                        callHandlerAdded0(newCtx);
                    }
                });
                return this;
            }
        }
        callHandlerAdded0(newCtx);
        return this;
    }
複製程式碼

addFirst方法先檢查新增的ChannelHandler是否可以共享(判斷共享的方法是對於每個channel當前ChannelHandler是否需要不同的狀態),再建立ChannelHandler的上下文關係,使ChannelHandler以連結串列方式存在於ChannelPipeline中。當ChannelHandler新增成功後,再呼叫ChannelHandlerhandlerAdded方法。其它的新增方式和addFirst類似。

事件觸發

fireChannelActive方法為例:

    public final ChannelPipeline fireChannelActive() {
        AbstractChannelHandlerContext.invokeChannelActive(head);
        return this;
    }
複製程式碼

HeadContext的head開始,依次觸發下一個ChannelHandlerchannelActive方法。

本篇簡單介紹了ChannelPipeline的相關概念,當ChannelHandler介紹完後,再具體介紹ChannelPipeline中的HeadContextTailContext

文中帖的程式碼註釋全在:KAMIJYOUDOUMA, 有興趣的童鞋可以關注一下。


本篇到此結束,如果讀完覺得有收穫的話,歡迎點贊、關注、加公眾號【貳級天災】,查閱更多精彩歷史!!!

Netty原始碼分析(七):初識ChannelPipeline

相關文章