Netty源碼分析(七):初識ChannelPipeline

ChannelPipeline單看名稱就能夠知道Channel的管道。本篇將結合它的默認實現類DefaultChannelPipeline來對它作一個簡單的介紹。git

示例圖

上圖是官方提供的 ChannelPipeline的事例圖。IO請求經由 ChannelOutboundHandlerChannelOutboundHandler處理以後寫出到服務端,服務接收到讀入後,由 ChannelInboundHandler依次處理。 下面來看下 DefaultChannelPipeline的類圖:
DefaultChannelPipeline實現了 ChannelPipeline接口,而 ChannelPipeline又繼承了 ChannelInboundInvokerChannelOutboundInvokerIterableChannelInboundInvoker:發起對 ChannelPipeline中下一個 ChannelInboundHandler的方法的調用。 ChannelOutboundInvoker:發起對 ChannelPipeline中下一個 ChannelOutboundHandler的方法的調用。 Iterable:可遍歷 ChannelPipeline中的 ChannelHandlerNioEventLoop繼承自 SingleThreadEventLoop,而 SingleThreadEventLoop又繼承自 SingleThreadEventExecutorSingleThreadEventExecutor內部持有一個Thread對象,是 Netty多線程的基礎。 能夠認爲, 一個 NioEventLoop與一個特定的線程進行了綁定,而且在其生命週期內,綁定的線程都不會再改變。

DefaultChannelPipeline

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

ChannelHandler的增減

addFirst方法爲例:bash

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方法爲例:ide

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

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

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

文中帖的代碼註釋全在:KAMIJYOUDOUMA, 有興趣的童鞋能夠關注一下。this


本篇到此結束,若是讀完以爲有收穫的話,歡迎點贊、關注、加公衆號【貳級天災】,查閱更多精彩歷史!!! spa

相關文章
相關標籤/搜索