溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

什么是Netty事件傳播

發(fā)布時(shí)間:2021-06-23 14:10:39 來(lái)源:億速云 閱讀:399 作者:chen 欄目:編程語(yǔ)言

本篇內(nèi)容主要講解“什么是Netty事件傳播”,感興趣的朋友不妨來(lái)看看。本文介紹的方法操作簡(jiǎn)單快捷,實(shí)用性強(qiáng)。下面就讓小編來(lái)帶大家學(xué)習(xí)“什么是Netty事件傳播”吧!

Netty高性能的背后,蘊(yùn)含著優(yōu)秀的設(shè)計(jì)。 今天我們從源碼角度詳細(xì)介紹Netty中ChannelPipeline的事件,以及這些事件是如何在ChannelPipeline中傳播的。

ChannelPipeline

ChannelPipeline是負(fù)責(zé)管理ChannelHandler的有序容器。 其內(nèi)部維護(hù)著一個(gè)由ChannelHandlerContext做為節(jié)點(diǎn)的雙向鏈表。 Netty上的事件便是通過(guò)這個(gè)鏈表進(jìn)行傳播的。

一圖勝千言

什么是Netty事件傳播

ChannelPipeline需要注意以下幾個(gè)關(guān)鍵點(diǎn):

  • Netty事件分為入站事件(inbound_event)和出站事件(outbound_event),入站事件由 InboundHandler 處理,出站事件由 OutboundHandler 處理。

  • 事件通過(guò)ChannelHandlerContext進(jìn)行傳播,入站事件順序傳播,出站事件逆序傳播。

  • 事件是顯示觸發(fā)的。(handler處理事件后,若要傳遞給下一個(gè)handler,必須顯示調(diào)用ChannelHandlerContext里的方法)

其中, 入站事件包括:

  • firefireChannelRegistered

  • fireChannelUnregistered

  • fireChannelActive

  • fireChannelInactive

  • fireChannelRead

  • fireChannelReadComplete

  • fireUserEventTriggered

  • fireChannelWritabilityChanged

  • fireExceptionCaught

出站事件包括:

  • bind

  • connect

  • disconnect

  • close

  • deregister

  • read

  • write

  • flush

  • writeAndFlush

handler里可以觸發(fā)任意的事件,即在InboundHandler里可以觸發(fā)出站事件,而OutboundHandler里也可以觸發(fā)入站事件。但注意不要出現(xiàn)事件的死循環(huán)。

更進(jìn)一步的,我們從源碼上去解讀ChannelPipeline的幾個(gè)要點(diǎn):

  • ChannelPipeline實(shí)例化后便提供了一個(gè)頭節(jié)點(diǎn)和一個(gè)尾節(jié)點(diǎn)的雙向鏈表

    protected DefaultChannelPipeline(Channel channel) {
        this.channel = ObjectUtil.checkNotNull(channel, "channel");
        succeededFuture = new SucceededChannelFuture(channel, null);
        voidPromise =  new VoidChannelPromise(channel, true);

        tail = new TailContext(this);   //尾節(jié)點(diǎn)
        head = new HeadContext(this);   //頭節(jié)點(diǎn)

        // 通過(guò)前驅(qū)與后續(xù)引用,形成一個(gè)雙向鏈表
        head.next = tail;
        tail.prev = head;
    }
  • 頭節(jié)點(diǎn)被標(biāo)記為outbound和inboud,尾節(jié)點(diǎn)標(biāo)記為inboud。(在下面的ChannelHandlerContext會(huì)介紹其作用)

  • 頭節(jié)點(diǎn)的入站處理程序會(huì)觸發(fā)新的入站事件,出站處理程序會(huì)調(diào)用unsafe對(duì)象的操作(將數(shù)據(jù)輸出到Sokect)。

  • 尾節(jié)點(diǎn)的入站處理程序是空處理或回收資源操作,出站處理程序觸發(fā)新的出站事件。

    HeadContext(DefaultChannelPipeline pipeline) {
        super(pipeline, null, HEAD_NAME, true, true);   // outbound=true
        unsafe = pipeline.channel().unsafe();   // 出站事件傳播到了頭節(jié)點(diǎn)后,便調(diào)用該unsafe對(duì)象上的方法
        setAddComplete();
    }

    TailContext(DefaultChannelPipeline pipeline) {
        super(pipeline, null, TAIL_NAME, true, false);  // inboud=true
        setAddComplete();
    }

    protected void onUnhandledInboundMessage(Object msg) {
        try {
            logger.debug(
                    "Discarded inbound message {} that reached at the tail of the pipeline. " +
                            "Please check your pipeline configuration.", msg);
        } finally {
            ReferenceCountUtil.release(msg);    // 釋放引用,當(dāng)引用為0時(shí),便可回收內(nèi)存空間
        }
    }

    protected void onUnhandledInboundChannelReadComplete() {    // 空處理
    }

    @Override
    public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception {
        unsafe.write(msg, promise);     // 通過(guò)unsafe將數(shù)據(jù)輸出
    }
  • 在Channel和ChannelPineline上的事件會(huì)傳遞給頭節(jié)點(diǎn)(入站)或尾節(jié)點(diǎn)(出站)。(再配合其他節(jié)點(diǎn)的handler,就可以形成了從頭到尾(或從尾到頭)依次傳播的事件)

    @Override
    public final ChannelPipeline fireChannelActive() {
        AbstractChannelHandlerContext.invokeChannelActive(head); //觸發(fā)head節(jié)點(diǎn)入站事件
        return this;
    }

    @Override
    public final ChannelFuture writeAndFlush(Object msg) {
        return tail.writeAndFlush(msg); // 觸發(fā)tail節(jié)點(diǎn)出站事件
    }
  • addXXX(ChannelHandler)會(huì)實(shí)例化一個(gè)含handler的ChannelHandlerContext對(duì)象,并插入鏈表。

  • addFirst在頭節(jié)點(diǎn)后插入新節(jié)點(diǎn),addLass在尾節(jié)點(diǎn)前插入新節(jié)點(diǎn)。

private AbstractChannelHandlerContext newContext(EventExecutorGroup group, String name, ChannelHandler handler) {
        return new DefaultChannelHandlerContext(this, childExecutor(group), name, handler); // 實(shí)例化含handler的ChannelHandlerContext對(duì)象
    }

    private void addFirst0(AbstractChannelHandlerContext newCtx) {
        AbstractChannelHandlerContext nextCtx = head.next;
        newCtx.prev = head;
        newCtx.next = nextCtx;
        head.next = newCtx;     // 新節(jié)點(diǎn)插入頭結(jié)點(diǎn)后面
        nextCtx.prev = newCtx;
    }

    private void addLast0(AbstractChannelHandlerContext newCtx) {
        AbstractChannelHandlerContext prev = tail.prev;
        newCtx.prev = prev;
        newCtx.next = tail;
        prev.next = newCtx;
        tail.prev = newCtx;     // 新節(jié)點(diǎn)插入尾節(jié)點(diǎn)前面
    }

ChannelHandlerContext

ChannelHandlerContext是ChannelPipeline雙向鏈表中的節(jié)點(diǎn)。 它是連接ChannelHandler和ChannelPipeline的橋梁。有了它ChannelHandler才有機(jī)會(huì)響應(yīng)并處理ChannelPipeline中的事件。

其源碼不復(fù)雜,其中ChannelHandlerContext的findContextInbound/findContextOutbound 是實(shí)現(xiàn)入站事件傳遞給InboundHandler出站事件傳遞給OutboundHandler的關(guān)鍵。 其實(shí)現(xiàn)也比較簡(jiǎn)單,就是判斷context的后續(xù)(入站事件)/前驅(qū)(出站事件)節(jié)點(diǎn)對(duì)應(yīng)的handler實(shí)現(xiàn)是否是inbound/outbound,如果不是則遍歷下一個(gè)節(jié)點(diǎn),直至尾節(jié)點(diǎn)/頭節(jié)點(diǎn)。

而在上面的分析中,我們已經(jīng)知道尾節(jié)點(diǎn)實(shí)例化時(shí),inbound被設(shè)置為ture,頭節(jié)點(diǎn)實(shí)例化時(shí),outbound被設(shè)置為ture。 這便形成的遍歷的終止條件。

    private AbstractChannelHandlerContext findContextInbound() {
        AbstractChannelHandlerContext ctx = this;
        do {
            ctx = ctx.next;
        } while (!ctx.inbound); //直到尾節(jié)點(diǎn),因?yàn)槲补?jié)點(diǎn)inbound在Pipeline中被定義為Ture
        return ctx;
    }

    private AbstractChannelHandlerContext findContextOutbound() {
        AbstractChannelHandlerContext ctx = this;
        do {
            ctx = ctx.prev;
        } while (!ctx.outbound);//直到頭節(jié)點(diǎn),因?yàn)轭^節(jié)點(diǎn)outbound在Pipeline中被定義為Ture
        return ctx;
    }

正是由于Netty這些優(yōu)秀的設(shè)計(jì),才使得其高性能下,仍然被靈活使用。 因此也被大家所接受并深愛著。


到此,相信大家對(duì)“什么是Netty事件傳播”有了更深的了解,不妨來(lái)實(shí)際操作一番吧!這里是億速云網(wǎng)站,更多相關(guān)內(nèi)容可以進(jìn)入相關(guān)頻道進(jìn)行查詢,關(guān)注我們,繼續(xù)學(xué)習(xí)!

向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI