Netty源碼分析(二)服務(wù)端 Channel 初始化原理

1. 嘮叨

及時(shí)分享學(xué)習(xí)所得。希望與您共勉,一起學(xué)習(xí)共同進(jìn)步。

2. 服務(wù)端 Channel 初始化

(重點(diǎn))我們還是先抓重點(diǎn)。下面是初始化 Netty 服務(wù)端 Channel 的主線,請(qǐng)牢記。

1. ServerBootstrap.bind(int inetPort)
2. AbstractBootstrap.bind(SocketAddress localAddress)
3. AbstractBootstrap.doBind(final SocketAddress localAddress)
4. AbstractBootstrap.initAndRegister()
5. ServerBootstrap.init(Channel channel)

前 4 步,與上一講服務(wù)端 Channel 創(chuàng)建原理一致。所以,初始化流程都在 ServerBootstrap.init 中

2.1 一起看源碼

(嘮叨)又到了有趣的查看源碼環(huán)節(jié)。現(xiàn)在打開您的 IDE 我們一起走一遍上面的流程。我們看到 ServerBootstrap.init 中大部分邏輯都是在初始化與創(chuàng)建對(duì)象。嗑...嗑...嗑...對(duì)本章就在學(xué)習(xí)初始化原理。相當(dāng)正確沒跑題。

(重點(diǎn))那初始化了什么?又創(chuàng)建了什么?

  1. 初始化 NioServerSocketChannel 的 config 與 attributes
  2. 在 pipeline 中添加 config.handler()
  3. 創(chuàng)建 ServerBootstrapAcceptor(連接器)并添加到 pipeline 中

源碼 1

// 我是 ServerBootstrap 類的 init 方法源碼
void init(Channel channel) throws Exception {
        // 初始化 NioServerSocketChannel 的 config 與 attributes
        final Map<ChannelOption<?>, Object> options = options0();
        synchronized (options) {
            channel.config().setOptions(options);   // 1
        }

        final Map<AttributeKey<?>, Object> attrs = attrs0();
        synchronized (attrs) {
            for (Entry<AttributeKey<?>, Object> e: attrs.entrySet()) {
                @SuppressWarnings("unchecked")
                AttributeKey<Object> key = (AttributeKey<Object>) e.getKey();
                channel.attr(key).set(e.getValue());  // 2
            }
        }

        ChannelPipeline p = channel.pipeline();

        final EventLoopGroup currentChildGroup = childGroup;
        final ChannelHandler currentChildHandler = childHandler;
        final Entry<ChannelOption<?>, Object>[] currentChildOptions;
        final Entry<AttributeKey<?>, Object>[] currentChildAttrs;
        synchronized (childOptions) {
            currentChildOptions = childOptions.entrySet().toArray(newOptionArray(childOptions.size())); 
        }
        synchronized (childAttrs) {
            currentChildAttrs = childAttrs.entrySet().toArray(newAttrArray(childAttrs.size())); 
        }

        p.addLast(new ChannelInitializer<Channel>() {
            @Override
            public void initChannel(Channel ch) throws Exception {
                final ChannelPipeline pipeline = ch.pipeline();
                ChannelHandler handler = config.handler();  // 3
                if (handler != null) {
                    pipeline.addLast(handler);  // 在 pipeline 中添加 config.handler()
                }

                // We add this handler via the EventLoop as the user may have used a ChannelInitializer as handler.
                // In this case the initChannel(...) method will only be called after this method returns. Because
                // of this we need to ensure we add our handler in a delayed fashion so all the users handler are
                // placed in front of the ServerBootstrapAcceptor.
                ch.eventLoop().execute(new Runnable() {
                    @Override
                    public void run() {
                        // 創(chuàng)建 ServerBootstrapAcceptor(連接器)并添加到 pipeline 中
                        pipeline.addLast(new ServerBootstrapAcceptor(
                                currentChildGroup, currentChildHandler, currentChildOptions, currentChildAttrs));  
                    }
                });
            }
        });
    }

2.2 出師了

恭喜您,您已經(jīng)掌握了服務(wù)端 Channel 的初始化原理。這次時(shí)候是真的,源碼也確實(shí)很簡單。是不是沒什么疑問了?真的沒有了?那么請(qǐng)嘗試回答這幾個(gè)問題 channel.config() 是什么?channel.attr 是什么?ChannelHandler handler 是什么?ServerBootstrapAcceptor 中的 4 個(gè)參數(shù)又什么是呢?(我又來賣關(guān)子了,你能怎樣?)如果以上問題您都清楚,那么恭喜您真的懂了。否則,我們繼續(xù)研究。

2.3 channel.config() 是什么

其實(shí)我上節(jié)講過,有圖有真相


圖 1

所以 NioServerSocketChannel 的配置保存在 ServerSocketChannelConfig 的實(shí)例對(duì)象 config 中,它是在 NioServerSocketChannel 的構(gòu)造函數(shù)中創(chuàng)建的。

2.4 channel.attr 是什么

如果你已經(jīng)打開了 IDE 此時(shí)你會(huì)發(fā)現(xiàn)它是 DefaultAttributeMap 中的方法。
(嘮叨)慌了東西越來越多,每次看開源代碼都是這樣,調(diào)用層次越來越深。最后直到迷失、放棄。
不急,下面我?guī)湍治鲆幌隆?/p>

1. NioServerSocketChannel extends AbstractNioMessageChannel
2. AbstractNioMessageChannel extends AbstractNioChannel
3. AbstractNioChannel extends AbstractChannel
4. AbstractChannel extends DefaultAttributeMap

怎么樣?懂了嗎?DefaultAttributeMap 是 NioServerSocketChannel 的爸爸。那它的 attr 自然也就被孩子繼承了。它里面存儲(chǔ)我們自定義的一些屬性(key,value)。

2.5 ChannelHandler handler 是什么

它是通過 AbstractBootstrapConfig 的 handler 方法獲取的

    public final ChannelHandler handler() {
        return bootstrap.handler();
    }

而 bootstrap.handler() 調(diào)用了 AbstractBootstrap 的 handler 方法,最終直接返回 handler

    final ChannelHandler handler() {
        return handler;
    }

現(xiàn)在我又需要上圖了

圖 2

由圖可知,它就是在第一節(jié),源碼 1 標(biāo)注 6 處我們傳入的 ServerHandler (這是一個(gè)自定義的 handler)。

2.6 ServerBootstrapAcceptor 中的 4 個(gè)參數(shù)是什么

currentChildGroup 就是 childGroup。 而 childGroup 需要參看 圖 2 源碼標(biāo)準(zhǔn) 2 處,我們調(diào)用了 ServerBootstrap 的 group(EventLoopGroup parentGroup, EventLoopGroup childGroup) 方法。所以,childGroup 就是我們傳入的 workerGroup

    public ServerBootstrap group(EventLoopGroup parentGroup, EventLoopGroup childGroup) {
        // 省略
        this.childGroup = childGroup;
        return this;
    }

currentChildHandler 就是 childHandler。而 childHandler 需要參看 圖 2 源碼標(biāo)準(zhǔn) 7 處,我們調(diào)用了 ServerBootstrap 的 childHandler(ChannelHandler childHandler) 方法。所以,childHandler 就是我們傳入的 ChannelInitializer
同理 currentChildOptions 和 currentChildAttrs 也很容易查找到,這里留給您自行分析。
通過以上分析,相信您已經(jīng)掌握了服務(wù)端 Channel 的初始化原理。
最后,感謝您的閱讀,希望以上內(nèi)容對(duì)您有所幫助。如果有疑問,歡迎留言與我討論。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容