最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Netty如何自定義編碼解碼器

 更新時間:2025年03月06日 10:35:31   作者:帥氣的人123  
Netty自定義編碼解碼器:InboundHandler處理入棧數(shù)據(jù),OutboundHandler處理出棧數(shù)據(jù),解碼器繼承ByteToMessageDecoder,編碼器繼承MessageToByteEncoder,ReplayingDecoder簡化了解碼邏輯,但可能因異常重試導致性能下降

Netty 自定義編碼解碼器

入棧:InboundHandler ,出棧:OutboundHandler。Netty 構建 chain 來處理業(yè)務。

自定義一個解碼器

解碼器主要是對客戶端發(fā)送的消息進行解碼處理,所以他是一個入棧的處理器,因此他會有一個入棧的標識ibound=true;

解碼器一般我都們都會基層 Netty 提供給的一個實現(xiàn)類來實現(xiàn)自己的解碼邏輯 -> io.netty.handler.codec.ByteToMessageDecoder 這就是解碼的抽象類,默認我們要實現(xiàn)一個抽象方法

com.netty.codec.custom.InboundAndOutboundHandler#decode 

這個方法有大概三個參數(shù);

  • ChannelHandlerContext channelHandlerContext 這個是上下文信息,可以獲取通道、管道等信息。
  • ByteBuf byteBuf 客戶端發(fā)送的消息就是存在這個參數(shù)的對象里面我們要通過這個對象的read***方法讀取我們需要的數(shù)據(jù)類型,可以是 LongByte 等類型的數(shù)據(jù)然后我們可以就可以轉換成為我們需要的格式。
  • List<Object> list 集合,將解碼后的數(shù)據(jù)傳遞給下一個inboundHandler 處理類。

代碼示例

@Override
protected void decode(ChannelHandlerContext channelHandlerContext, ByteBuf byteBuf, List<Object> list) {
    // Long => 8 byte
    if (byteBuf.readableBytes() >= 8) {
        list.add(byteBuf.readLong());
    } else log.warn("字節(jié)數(shù)異常 => {}", byteBuf.readableBytes());
}

這樣我們就實現(xiàn)了一個簡單的解碼器。

自定義一個編碼器

解碼器主要是對服務端將要發(fā)送給客戶端的消息進行編碼處理,所以他是一個出棧的處理器,因此他會有一個入棧的標識outbound=true;

使用 Netty 提供的抽象類 => io.netty.handler.codec.MessageToByteEncoder<T> 泛型 T 表示你要發(fā)送的消息的類型,實現(xiàn)抽象方法 => com.netty.codec.custom.OutboundHandler#encode 方法的參數(shù)有三個:

  • ChannelHandlerContext channelHandlerContext 這個是上下文信息,可以獲取通道、管道等信息。
  • Long msg 服務端要發(fā)送給客戶端的消息
  • ByteBuf byteBuf

代碼示例

@Override
protected void encode(ChannelHandlerContext channelHandlerContext, Long msg, ByteBuf byteBuf) {
    byteBuf.writeLong(msg);
    log.info("發(fā)送消息成功");
}

后續(xù) -> io.netty.handler.codec.ReplayingDecoder

ByteToMessage 其實在使用過程中會遇到一些問題,例如:

當我們的解碼器中想要將字節(jié)轉換為一個 Integer ,我們知道 Integer 是四個字節(jié)的,但是如果在讀取的時候不夠四個字節(jié),這個時候我們就需要做一些判斷邏輯 => if (byteBuf.readableBytes() >= 4) 當這個返回值為 true 的時候我么就可以繼續(xù)執(zhí)行解碼的邏輯。

那我們怎么可以跳過這一步不判斷直接進行我們的轉換邏輯呢?

這個時候就可以使用 Netty 的

io.netty.handler.codec.ReplayingDecoder

可以不用判斷可讀字節(jié)數(shù)的原理:

ReplayingDecoderByteToMessage 的子類,源碼如下:

public abstract class ReplayingDecoder<S> extends ByteToMessageDecoder {
    ...
}

ReplayingDecoder 的秘密就是對 ByteToMessageCallDecode(...) 方法的重寫,觀摩一下具體實現(xiàn):

@Override
protected void callDecode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) {
    replayable.setCumulation(in);
    try {
        while (in.isReadable()) {
            int oldReaderIndex = checkpoint = in.readerIndex();
            int outSize = out.size();

            if (outSize > 0) {
                fireChannelRead(ctx, out, outSize);
                out.clear();

                // Check if this handler was removed before continuing with decoding.
                // If it was removed, it is not safe to continue to operate on the buffer.
                //
                // See:
                // - https://github.com/netty/netty/issues/4635
                if (ctx.isRemoved()) {
                    break;
                }
                outSize = 0;
            }

            S oldState = state;
            int oldInputLength = in.readableBytes();
            try {
                decodeRemovalReentryProtection(ctx, replayable, out);

                // Check if this handler was removed before continuing the loop.
                // If it was removed, it is not safe to continue to operate on the buffer.
                //
                // See https://github.com/netty/netty/issues/1664
                if (ctx.isRemoved()) {
                    break;
                }

                if (outSize == out.size()) {
                    if (oldInputLength == in.readableBytes() && oldState == state) {
                        throw new DecoderException(
                                StringUtil.simpleClassName(getClass()) + ".decode() must consume the inbound " +
                                "data or change its state if it did not decode anything.");
                    } else {
                        // Previous data has been discarded or caused state transition.
                        // Probably it is reading on.
                        continue;
                    }
                }
            } catch (Signal replay) {
                replay.expect(REPLAY);

                // Check if this handler was removed before continuing the loop.
                // If it was removed, it is not safe to continue to operate on the buffer.
                //
                // See https://github.com/netty/netty/issues/1664
                if (ctx.isRemoved()) {
                    break;
                }

                // Return to the checkpoint (or oldPosition) and retry.
                int checkpoint = this.checkpoint;
                if (checkpoint >= 0) {
                    in.readerIndex(checkpoint);
                } else {
                    // Called by cleanup() - no need to maintain the readerIndex
                    // anymore because the buffer has been released already.
                }
                break;
            }

            if (oldReaderIndex == in.readerIndex() && oldState == state) {
                throw new DecoderException(
                       StringUtil.simpleClassName(getClass()) + ".decode() method must consume the inbound data " +
                       "or change its state if it decoded something.");
            }
            if (isSingleDecode()) {
                break;
            }
        }
    } catch (DecoderException e) {
        throw e;
    } catch (Exception cause) {
        throw new DecoderException(cause);
    }
}

實現(xiàn)不需要判斷的邏輯就是因為

int oldReaderIndex = checkpoint = in.readerIndex(); 

如果在執(zhí)行過程中出現(xiàn)異常就會在代碼中重置 index

總結

雖然 ReplayingDecoder節(jié)約了判斷的邏輯,但是從他的代碼實現(xiàn)邏輯看到是通過拋出異常來不斷的重試,所以在某些特殊的情況下會造成性能的下降。所以還是再選擇的時候要根據(jù)自己的實際需求來判斷是使用 ByteToMessage 還是使用 ReplayingDecoder。

以上為個人經驗,希望能給大家一個參考,也希望大家多多支持腳本之家。

相關文章

  • Spring實現(xiàn)內置監(jiān)聽器

    Spring實現(xiàn)內置監(jiān)聽器

    這篇文章主要介紹了Spring 實現(xiàn)自定義監(jiān)聽器案例,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧,希望能給你帶來幫助
    2021-07-07
  • Spring Boot + Kotlin + Gradle 構建現(xiàn)代化后端應用(常見問題及方案)

    Spring Boot + Kotlin + Gradle 

    本文將系統(tǒng)梳理使用Spring Boot、Kotlin 和 Gradle(Kotlin DSL) 開發(fā)項目的全流程,涵蓋項目初始化、核心開發(fā)要點、多模塊架構設計以及常見問題解決方案,幫助開發(fā)者快速上手并規(guī)避典型陷阱,感興趣的朋友跟隨小編一起看看吧
    2025-11-11
  • Java String.join()從入門到高階架構實踐

    Java String.join()從入門到高階架構實踐

    本文詳細介紹了Java 8中引入的String.join()方法,探討了其設計哲學、核心技術原理、高級用法、架構模式、性能優(yōu)化以及實際應用場景,String.join()不僅簡化了字符串拼接操作,還提供了更好的性能和可維護性,感興趣的朋友跟隨小編一起看看吧
    2026-01-01
  • springsecurity第三方授權認證的項目實踐

    springsecurity第三方授權認證的項目實踐

    Spring security 是一個強大的和高度可定制的身份驗證和訪問控制框架,本文主要介紹了springsecurity第三方授權認證的項目實踐,具有一定的參考價值,感興趣可以了解一下
    2023-08-08
  • java中調用GDAL DLL的實現(xiàn)方法

    java中調用GDAL DLL的實現(xiàn)方法

    本篇文章是對java中調用GDAL DLL的實現(xiàn)方法進行了詳細的分析介紹,需要的朋友參考下
    2013-05-05
  • SpringBoot訪問windows共享文件的方法

    SpringBoot訪問windows共享文件的方法

    這篇文章主要介紹了SpringBoot訪問windows共享文件,項目使用minio存儲且不在同一臺服務器上,為了優(yōu)化速度決定使用windows共享功能進行文件傳輸,本文結合實例代碼給大家介紹的非常詳細,需要的朋友可以參考下
    2023-02-02
  • Mybatis中的PageHelper的執(zhí)行流程分析

    Mybatis中的PageHelper的執(zhí)行流程分析

    這篇文章主要介紹了Mybatis的PageHelper執(zhí)行流程,本文給大家介紹介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2022-02-02
  • Java語言實現(xiàn)對MySql數(shù)據(jù)庫中數(shù)據(jù)的增刪改查操作的代碼

    Java語言實現(xiàn)對MySql數(shù)據(jù)庫中數(shù)據(jù)的增刪改查操作的代碼

    這篇文章主要介紹了Java語言實現(xiàn)對MySql數(shù)據(jù)庫中數(shù)據(jù)的增刪改查操作的代碼,實現(xiàn)了連接數(shù)據(jù)庫,和數(shù)據(jù)庫的增刪改查操作,有興趣的可以了解一下。
    2016-12-12
  • Java編程之雙重循環(huán)打印圖形

    Java編程之雙重循環(huán)打印圖形

    這篇文章主要介紹了Java編程之雙重循環(huán)打印圖形,屬于Java編程基礎練習部分,具有一定參考價值,需要的朋友可以了解下。
    2017-11-11
  • Java動態(tài)導出Word登記表的完整方案

    Java動態(tài)導出Word登記表的完整方案

    本文詳細講解如何使用 Java動態(tài)導出包含多人員報名表的Word文檔,每人占據(jù)獨立一頁,并支持動態(tài)表格行,我們對比了多種實現(xiàn)方案,最終推薦基于 Freemarker + XML模板或docx4j的靈活方式,并提供完整代碼示例與最佳實踐,助你高效實現(xiàn)復雜Word導出需求
    2025-07-07

最新評論

临泉县| 垦利县| 海城市| 宁夏| 沁水县| 剑河县| 左贡县| 元谋县| 石家庄市| 远安县| 新密市| 金秀| 栾城县| 肥西县| 荣昌县| 辽中县| 阿鲁科尔沁旗| 赤水市| 电白县| 称多县| 宜宾县| 龙山县| 额尔古纳市| 正定县| 枝江市| 鹤山市| 外汇| 梁山县| 庄浪县| 固原市| 林州市| 子洲县| 昆山市| 海阳市| 和政县| 太原市| 石台县| 丰县| 庄浪县| 广南县| 浠水县|