溫馨提示×

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

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

netty handler的執(zhí)行順序是什么

發(fā)布時(shí)間:2021-12-16 16:46:21 來(lái)源:億速云 閱讀:295 作者:iii 欄目:云計(jì)算

這篇文章主要介紹“netty handler的執(zhí)行順序是什么”,在日常操作中,相信很多人在netty handler的執(zhí)行順序是什么問(wèn)題上存在疑惑,小編查閱了各式資料,整理出簡(jiǎn)單好用的操作方法,希望對(duì)大家解答”netty handler的執(zhí)行順序是什么”的疑惑有所幫助!接下來(lái),請(qǐng)跟著小編一起來(lái)學(xué)習(xí)吧!

handler的概念,讓我想到了其他的一些東西,就好像servlet當(dāng)中的filter,spring當(dāng)中的interceptor。 在handler當(dāng)中,能夠完成各種各樣的工作,協(xié)議流的編解碼、特殊信息的攔截、請(qǐng)求數(shù)量的統(tǒng)計(jì)等等,或者可以這樣說(shuō),所有的業(yè)務(wù)層面的東西,都需要在handler當(dāng)中來(lái)完成。

我會(huì)按照上行和下行兩類來(lái)分析handler的執(zhí)行順序,今天先來(lái)下行的。

按照我最初的想象,所有的handler應(yīng)該都是同一類東西,那么我們業(yè)務(wù)執(zhí)行的方法,也就是我們繼承netty提供的父類之后,Override的方法,應(yīng)該是同一個(gè),可是我實(shí)際使用當(dāng)中發(fā)現(xiàn)不是這么回事,有時(shí)候是一個(gè)decode方法,有時(shí)候是一個(gè)messageReceived方法,這是什么道理?;谶@個(gè)困惑,才會(huì)有了今天的這篇文章。

首先是一個(gè)stacktrace的圖。

netty handler的執(zhí)行順序是什么

ProtocolAnaDecoder是我自己寫(xiě)的一個(gè)協(xié)議解析類,繼承自 ByteToMessageDecoder ,在這個(gè)類里面依次調(diào)用了3個(gè)方法,channelRead(),callDecode(),decode()。這其中decode,是我們自己實(shí)現(xiàn)的,其他2個(gè)方法來(lái)自父類。

再看另一個(gè)圖。

netty handler的執(zhí)行順序是什么

NettyServerHandler繼承自SimpleChannelInboundHandler,這里依次調(diào)用了channelRead(),messageReceived()這樣2個(gè)方法。

到此為止基本就解決了我的第一個(gè)疑惑,最初都來(lái)自channelRead。那么這個(gè) channelRead 雖然在各種handler當(dāng)中都有實(shí)現(xiàn),但是它的最初的定義來(lái)自ChannelHandler,這是一個(gè)interface。而它的實(shí)現(xiàn)ChannelHandlerAdapter,基本可以看做netty當(dāng)中所有handler的老祖宗。(這里之所以要說(shuō)基本,是因?yàn)橛?個(gè)web相關(guān)的handler interface,直接繼承了 ChannelHandler,但這個(gè)不是我們今天討論的重點(diǎn))

繼續(xù),就該是ChannelHandlerInvokerUtil.invokeChannelReadNow,看代碼吧。

    public static void invokeChannelReadNow(final ChannelHandlerContext ctx, final Object msg) {
        try {
            ctx.handler().channelRead(ctx, msg);
        } catch (Throwable t) {
            notifyHandlerException(ctx, t);
        }
    }

清楚明白,很好理解。

然后是DefaultChannelHandlerInvoker.invokeChannelRead,代碼如下:

@Override
    public void invokeChannelRead(final ChannelHandlerContext ctx, final Object msg) {
        if (msg == null) {
            throw new NullPointerException("msg");
        }

        if (executor.inEventLoop()) {
            invokeChannelReadNow(ctx, msg);
        } else {
            safeExecuteInbound(new Runnable() {
                @Override
                public void run() {
                    invokeChannelReadNow(ctx, msg);
                }
            }, msg);
        }
    }

executor.inEventLoop() ,當(dāng)前channel的 executor 是否處于時(shí)間循環(huán)當(dāng)中,好吧,到目前為止,我也不知道什么時(shí)候會(huì)走到else里面去,這里只好留待以后再去搞搞清楚了。

再往前走,DefaultChannelHandlerContext.fireChannelRead,代碼如下:

public ChannelHandlerContext fireChannelRead(Object msg) {
        DefaultChannelHandlerContext next = findContextInbound(MASK_CHANNEL_READ);
        next.invoker.invokeChannelRead(next, msg);
        return this;
    }

handler的依次執(zhí)行就在這里面體現(xiàn)了。

繼續(xù),DefaultChannelPipeline.fireChannelRead,代碼如下:

public ChannelPipeline fireChannelRead(Object msg) {
        head.fireChannelRead(msg);
        return this;
    }

好了,如果沒(méi)記錯(cuò)的話,我們最初聲明一個(gè)netty的時(shí)候,就是把一系列的handler加到了channel pipeline當(dāng)中。那么這一系列的handler在pipeline當(dāng)中是如何保存的呢。我首先先看一下 DefaultChannelPipeline 的構(gòu)造函數(shù):

public DefaultChannelPipeline(AbstractChannel channel) {
        if (channel == null) {
            throw new NullPointerException("channel");
        }
        this.channel = channel;

        TailHandler tailHandler = new TailHandler();
        tail = new DefaultChannelHandlerContext(this, null, generateName(tailHandler), tailHandler);

        HeadHandler headHandler = new HeadHandler(channel.unsafe());
        head = new DefaultChannelHandlerContext(this, null, generateName(headHandler), headHandler);

        head.next = tail;
        tail.prev = head;
    }

首先生命了一個(gè)tail和一個(gè)head,然后把這2個(gè)對(duì)象構(gòu)成了一個(gè)雙向鏈表。

再看一下addlast方法:

private void addLast0(final String name, DefaultChannelHandlerContext newCtx) {
        checkMultiplicity(newCtx);

        DefaultChannelHandlerContext prev = tail.prev;
        newCtx.prev = prev;
        newCtx.next = tail;
        prev.next = newCtx;
        tail.prev = newCtx;

        name2ctx.put(name, newCtx);

        callHandlerAdded(newCtx);
    }

很清楚,在鏈表當(dāng)中插入一個(gè)元素。再對(duì)照一下前面的代碼,首先從head開(kāi)始,但它并不完成實(shí)際工作,直接取它的next來(lái)執(zhí)行,之后依次便利鏈表。

到此,關(guān)于“netty handler的執(zhí)行順序是什么”的學(xué)習(xí)就結(jié)束了,希望能夠解決大家的疑惑。理論與實(shí)踐的搭配能更好的幫助大家學(xué)習(xí),快去試試吧!若想繼續(xù)學(xué)習(xí)更多相關(guān)知識(shí),請(qǐng)繼續(xù)關(guān)注億速云網(wǎng)站,小編會(huì)繼續(xù)努力為大家?guī)?lái)更多實(shí)用的文章!

向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