ByteToMessageDecoder分析

ByteToMessageDecoder

該方法提供了將 ByteBuf 轉(zhuǎn)化為對象的解碼器處理流程邪乍,具體的解碼規(guī)則交由子類去實現(xiàn)捅伤。

我們以讀操作 channelRead 為例來研究一下:

public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        if (msg instanceof ByteBuf) {
            // out 是一個鏈表,存放解碼成功的對象
            CodecOutputList out = CodecOutputList.newInstance();
            try {
                ByteBuf data = (ByteBuf) msg;
                // cumulation 中存放的是上次未處理完的半包消息
                first = cumulation == null;
                if (first) {
                    cumulation = data;
                } else {
                    // 本次處理难衰,需要把上次遺留的半包和本次數(shù)據(jù)拼接后钦无,一起處理
                    cumulation = cumulator.cumulate(ctx.alloc(), cumulation, data);
                }
                // 調(diào)用解碼器解碼消息
                callDecode(ctx, cumulation, out);
            } catch (DecoderException e) {
                throw e;
            } catch (Exception e) {
                throw new DecoderException(e);
            } finally {
                if (cumulation != null && !cumulation.isReadable()) {
                    numReads = 0;
                    cumulation.release();
                    cumulation = null;
                } else if (++ numReads >= discardAfterReads) {
                    numReads = 0;
                    discardSomeReadBytes();
                }

                int size = out.size();
                decodeWasNull = !out.insertSinceRecycled();
                // 如果有解碼成功的數(shù)據(jù),需要向后傳遞盖袭,讓其他 ChannelHandler 繼續(xù)處理
                fireChannelRead(ctx, out, size);
                out.recycle();
            }
        } else {
            ctx.fireChannelRead(msg);
        }
    }

    protected void callDecode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) {
        try {
            while (in.isReadable()) {
                int outSize = out.size();

                if (outSize > 0) {
                    // 如果有解碼成功的數(shù)據(jù)失暂,需要向后傳遞,讓其他 ChannelHandler 繼續(xù)處理
                    fireChannelRead(ctx, out, outSize);
                    out.clear();
                    // 如果當前 ChannelHandler 所屬 ctx 被剔除 pipeline 上下文鳄虱,就不需要繼續(xù)處理了
                    if (ctx.isRemoved()) {
                        break;
                    }
                    outSize = 0;
                }

                int oldInputLength = in.readableBytes();
                // 解碼
                decodeRemovalReentryProtection(ctx, in, out);

                if (ctx.isRemoved()) {
                    break;
                }

                if (outSize == out.size()) {
                    if (oldInputLength == in.readableBytes()) {
                        break;
                    } else {
                        continue;
                    }
                }

                if (oldInputLength == in.readableBytes()) {
                    throw new DecoderException(
                            StringUtil.simpleClassName(getClass()) +
                                    ".decode() did not read anything but decoded a message.");
                }

                if (isSingleDecode()) {
                    break;
                }
            }
        } catch (DecoderException e) {
            throw e;
        } catch (Exception cause) {
            throw new DecoderException(cause);
        }
    }

    final void decodeRemovalReentryProtection(ChannelHandlerContext ctx, ByteBuf in, List<Object> out)
            throws Exception {
        // 設置解碼器狀態(tài)為正在解碼弟塞,避免解碼過程中另一個線程調(diào)用了 handlerRemoved 把數(shù)據(jù)銷毀,造成混亂
        decodeState = STATE_CALLING_CHILD_DECODE;
        try {
            decode(ctx, in, out);
        } finally {
            // STATE_HANDLER_REMOVED_PENDING 表示在解碼過程中拙已,ctx 被移除决记,需要由當前線程來調(diào)用 handlerRemoved 
            boolean removePending = decodeState == STATE_HANDLER_REMOVED_PENDING;
            decodeState = STATE_INIT;
            if (removePending) {
                handlerRemoved(ctx);
            }
        }
    }

    // 具體的消息解碼算法,交給子類實現(xiàn)
    protected abstract void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception;    
?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末倍踪,一起剝皮案震驚了整個濱河市系宫,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌建车,老刑警劉巖扩借,帶你破解...
    沈念sama閱讀 218,640評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異缤至,居然都是意外死亡往枷,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,254評論 3 395
  • 文/潘曉璐 我一進店門凄杯,熙熙樓的掌柜王于貴愁眉苦臉地迎上來错洁,“玉大人,你說我怎么就攤上這事戒突⊥筒辏” “怎么了?”我有些...
    開封第一講書人閱讀 165,011評論 0 355
  • 文/不壞的土叔 我叫張陵膊存,是天一觀的道長导而。 經(jīng)常有香客問我,道長隔崎,這世上最難降的妖魔是什么今艺? 我笑而不...
    開封第一講書人閱讀 58,755評論 1 294
  • 正文 為了忘掉前任,我火速辦了婚禮爵卒,結果婚禮上虚缎,老公的妹妹穿的比我還像新娘。我一直安慰自己钓株,他們只是感情好实牡,可當我...
    茶點故事閱讀 67,774評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著轴合,像睡著了一般创坞。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上受葛,一...
    開封第一講書人閱讀 51,610評論 1 305
  • 那天题涨,我揣著相機與錄音,去河邊找鬼总滩。 笑死纲堵,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的咳秉。 我是一名探鬼主播婉支,決...
    沈念sama閱讀 40,352評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼澜建!你這毒婦竟也來了向挖?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,257評論 0 276
  • 序言:老撾萬榮一對情侶失蹤炕舵,失蹤者是張志新(化名)和其女友劉穎何之,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體咽筋,經(jīng)...
    沈念sama閱讀 45,717評論 1 315
  • 正文 獨居荒郊野嶺守林人離奇死亡溶推,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,894評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片蒜危。...
    茶點故事閱讀 40,021評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡虱痕,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出辐赞,到底是詐尸還是另有隱情部翘,我是刑警寧澤,帶...
    沈念sama閱讀 35,735評論 5 346
  • 正文 年R本政府宣布响委,位于F島的核電站新思,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏赘风。R本人自食惡果不足惜夹囚,卻給世界環(huán)境...
    茶點故事閱讀 41,354評論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望邀窃。 院中可真熱鬧荸哟,春花似錦、人聲如沸蛔翅。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,936評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽山析。三九已至堰燎,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間笋轨,已是汗流浹背秆剪。 一陣腳步聲響...
    開封第一講書人閱讀 33,054評論 1 270
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留爵政,地道東北人仅讽。 一個月前我還...
    沈念sama閱讀 48,224評論 3 371
  • 正文 我出身青樓,卻偏偏與公主長得像钾挟,于是被迫代替她去往敵國和親洁灵。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 44,974評論 2 355

推薦閱讀更多精彩內(nèi)容