1. 程式人生 > >Netty學習之旅------原始碼分析Netty解碼編碼器實現原理

Netty學習之旅------原始碼分析Netty解碼編碼器實現原理

package io.netty.handler.codec;

import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerAdapter;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.ChannelPromise;
import io.netty.util.ReferenceCountUtil;
import io.netty.util.internal.TypeParameterMatcher;


/**
 * {@link ChannelHandlerAdapter} which encodes message in a stream-like fashion from one message to an
 * {@link ByteBuf}.
 *
 *
 * Example implementation which encodes {@link Integer}s to a {@link ByteBuf}.
 *
 * <pre>
 *     public class IntegerEncoder extends {@link MessageToByteEncoder}<{@link Integer}> {
 *         {@code @Override}
 *         public void encode({@link ChannelHandlerContext} ctx, {@link Integer} msg, {@link ByteBuf} out)
 *                 throws {@link Exception} {
 *             out.writeInt(msg);
 *         }
 *     }
 * </pre>
 */
public abstract class MessageToByteEncoder<I> extends ChannelHandlerAdapter {

    private final TypeParameterMatcher matcher;
    private final boolean preferDirect;

    /**
     * @see {@link #MessageToByteEncoder(boolean)} with {@code true} as boolean parameter.
     */
    protected MessageToByteEncoder() {
        this(true);
    }

    /**
     * @see {@link #MessageToByteEncoder(Class, boolean)} with {@code true} as boolean value.
     */
    protected MessageToByteEncoder(Class<? extends I> outboundMessageType) {
        this(outboundMessageType, true);
    }

    /**
     * Create a new instance which will try to detect the types to match out of the type parameter of the class.
     *
     * @param preferDirect          {@code true} if a direct {@link ByteBuf} should be tried to be used as target for
     *                              the encoded messages. If {@code false} is used it will allocate a heap
     *                              {@link ByteBuf}, which is backed by an byte array.
     */
    protected MessageToByteEncoder(boolean preferDirect) {
        matcher = TypeParameterMatcher.find(this, MessageToByteEncoder.class, "I");
        this.preferDirect = preferDirect;
    }

    /**
     * Create a new instance
     *
     * @param outboundMessageType   The tpye of messages to match
     * @param preferDirect          {@code true} if a direct {@link ByteBuf} should be tried to be used as target for
     *                              the encoded messages. If {@code false} is used it will allocate a heap
     *                              {@link ByteBuf}, which is backed by an byte array.
     */
    protected MessageToByteEncoder(Class<? extends I> outboundMessageType, boolean preferDirect) {
        matcher = TypeParameterMatcher.get(outboundMessageType);
        this.preferDirect = preferDirect;
    }

    /**
     * Returns {@code true} if the given message should be handled. If {@code false} it will be passed to the next
     * {@link ChannelHandler} in the {@link ChannelPipeline}.
     */
    public boolean acceptOutboundMessage(Object msg) throws Exception {
        return matcher.match(msg);
    }

    @Override
    public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception {
        ByteBuf buf = null;
        try {
            if (acceptOutboundMessage(msg)) {
                @SuppressWarnings("unchecked")
                I cast = (I) msg;
                buf = allocateBuffer(ctx, cast, preferDirect);
                try {
                    encode(ctx, cast, buf);
                } finally {
                    ReferenceCountUtil.release(cast);
                }

                if (buf.isReadable()) {
                    ctx.write(buf, promise);
                } else {
                    buf.release();
                    ctx.write(Unpooled.EMPTY_BUFFER, promise);
                }
                buf = null;
            } else {
                ctx.write(msg, promise);
            }
        } catch (EncoderException e) {
            throw e;
        } catch (Throwable e) {
            throw new EncoderException(e);
        } finally {
            if (buf != null) {
                buf.release();
            }
        }
    }

    /**
     * Allocate a {@link ByteBuf} which will be used as argument of {@link #encode(ChannelHandlerContext, I, ByteBuf)}.
     * Sub-classes may override this method to returna {@link ByteBuf} with a perfect matching {@code initialCapacity}.
     */
    protected ByteBuf allocateBuffer(ChannelHandlerContext ctx, @SuppressWarnings("unused") I msg,
                               boolean preferDirect) throws Exception {
        if (preferDirect) {
            return ctx.alloc().ioBuffer();
        } else {
            return ctx.alloc().heapBuffer();
        }
    }

    /**
     * Encode a message into a {@link ByteBuf}. This method will be called for each written message that can be handled
     * by this encoder.
     *
     * @param ctx           the {@link ChannelHandlerContext} which this {@link MessageToByteEncoder} belongs to
     * @param msg           the message to encode
     * @param out           the {@link ByteBuf} into which the encoded message will be written
     * @throws Exception    is thrown if an error accour
     */
    protected abstract void encode(ChannelHandlerContext ctx, I msg, ByteBuf out) throws Exception;
}
總結:

相關推薦

Netty學習------原始碼分析Netty解碼編碼實現原理

package io.netty.handler.codec; import io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; import io.netty.channel.ChannelHandler; import io.netty.c

Netty學習------原始碼分析Netty執行緒本地分配機制與PooledByteBuf執行緒級物件池原理分析

final PoolArena<byte[]> heapArena; //使用輪叫輪詢機制,每個執行緒從heapArena[]中獲取一個,用於記憶體分配。 final PoolArena<ByteBuffer> directArena;

Netty學習----原始碼分析Netty記憶體洩漏檢測

1、圖說Netty直接記憶體管理 2、Netty 直接記憶體的使用示例 ByteBuf buf = Unpooled.directBuffer(512); System.out.println(buf); // Si

Netty學習----原始碼分析記憶體分配與釋放原理

static PooledHeapByteBuf newInstance(int maxCapacity) { PooledHeapByteBuf buf = RECYCLER.get(); buf.setRefCnt(1); buf.maxCapacity(m

Netty學習----ThreadLocal原理分析與效能優化思考(思考篇)

/** * Returns the value in the current thread's copy of this * thread-local variable. If the variable has no value for the

Netty學習----ByteBuf原始碼解讀初探UnpooledHeapByteBuf、UnpooledDirectByteBuf

前沿:     在讀原始碼的過程中我發現有如下幾個點,感覺有問題: 1)UnpooledDirectByteBuf的 capacity(int newCapacity)方法,在readerIndex大於或等於newCapacity時,此時不需要將原ByteBuffer中的資

Netty學習篇⑥--ByteBuf原始碼分析

什麼是ByteBuf? ByteBuf在Netty中充當著非常重要的角色;它是在資料傳輸中負責裝載位元組資料的一個容器;其內部結構和陣列類似,初始化預設長度為256,預設最大長度為Integer.MAX_VALUE。 ByteBuf資料結構 * <pre> * +-----------

springMVC原始碼學習addFlashAttribute原始碼分析

本文主要從falshMap初始化,存,取,消毀來進行原始碼分析,springmvc版本4.3.18。關於使用及驗證請參考另一篇https://www.cnblogs.com/pu20065226/p/10032048.html 1.初始化和呼叫,首先是入springMVC 入口webmvc包中org.spr

go 原始碼學習---Tail 原始碼分析

已經有兩個月沒有寫部落格了,也有好幾個月沒有看go相關的內容了,由於工作原因最近在做java以及大資料相關的內容,導致最近工作較忙,部落格停止了更新,正好想撿起之前go的東西,所以找了一個原始碼學習 這個也是之前用go寫日誌收集的時候用到的一個包 :github.com/hpcloud/tail, 這次就學

SpringMVC原始碼學習request處理流程 springMVC原始碼學習地址 springMVC原始碼學習addFlashAttribute原始碼分析 java reflect反射呼叫方法invoke

目的:為看原始碼提供呼叫地圖,最長呼叫邏輯深度為8層,反正我是springMVC原始碼學習地址看了兩週才理出來的。 1.處理流程(版本為4.3.18) 入口為spring-webmvc-4.3.18.RELEASE.jar中org.springframework.web.servlet.Dispatche

Python學習—Day07(生成器與叠代)

討論 三次 iterable 結果 fis post 工作 映射 我們 前言     本篇博客主要專註於解決函數中的一個重要知識點——生成器與叠代器。不管是面試還是工作,生成器與叠代器在實際工作中的運用可以說是非常多,從我們第一天開始學習for循環來遍歷字典,列表等數據類

小程式學習---表單元件 picker picker-view 實現日期 區域 聯動選擇

Page({ /** * 頁面的初始資料 */ data: { cityList: ['北京', '上海', '深圳', '廣州'], cityIndex: 1, time: '17:01', date: '2018-6-28',

WebService學習(六)使用Apache Axis2實現WebService客戶端呼叫

上節介紹瞭如何使用Axis2 釋出一個WebService,Axis2除了為我們編寫WebService應用帶來了便利,也同樣簡化的客戶端呼叫的過程,本節在上節的基礎上使用Axis2自帶的工具生成客戶端呼叫輔助類,並實現客戶端呼叫程式碼的編寫。 1.將前面下載

Flask原始碼分析二:路由內部實現原理

前言 Flask是目前為止我最喜歡的一個Python Web框架了,為了更好的掌握其內部實現機制,這兩天準備學習下Flask的原始碼,將由淺入深跟大家分享下,其中Flask版本為1.1.1。 上次瞭解了Flask服務的啟動流程,今天我們來看下路由的內部實現機理。 Flask系列文章: Flask開發初探 F

原始碼分析 Alibaba sentinel 滑動視窗實現原理(文末附原理圖)

要實現限流、熔斷等功能,首先要解決的問題是如何實時採集服務(資源)呼叫資訊。例如將某一個介面設定的限流闊值 1W/tps,那首先如何判斷當前的 TPS 是多少?Alibaba Sentinel 採用滑動視窗來實現實時資料的統計。 > 溫馨提示:如果對原始碼不太感興趣,可以先跳到文末,看一下滑動視窗的設

Netty三:Netty服務端啟動原始碼分析,一梭子帶走!

# Netty服務端啟動流程原始碼分析 ![](//p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/d5be8808ccb54c318b5abd21f97bd37f~tplv-k3u1fbpfcp-zoom-1.image) ## 前記 哈嘍,自從上篇《Netty之旅

Netty四】你一定看得懂的Netty客戶端啟動原始碼分析

## 前言 前面小飛已經講解了`NIO`和`Netty`服務端啟動,這一講是`Client`的啟動過程。 原始碼系列的文章依舊還是遵循大白話+畫圖的風格來講解,本文`Netty`原始碼及以後的文章版本都基於:**4.1.22.Final** 本篇是以`NettyClient`啟動為切入點,帶大家一步步進

Netty學習路(六)-分隔符和定長解碼的應用

之前已經使用了LineBasedFrameDecoder解決TCP粘包問題,現在再學兩種解決TCP粘包的方法。 DelimiterBasedFrameDecoder:可以自動完成以分隔符做結束標誌的訊息的解碼,分隔符自定義。 FixedLengthFrameDecoder:

Netty學習路(九)-JBoss Marshalling編解碼

JBoss Marshalling 是一個Java物件序列化包,對JDK預設的序列化框架進行了優化,但又保持跟java.io.Serializable介面的相容,同時增加了一些可調的引數和附加的特性。 Marshalling開發環境準備 下載相關的Marshalling類庫:地址,將

Netty學習路(七)-編解碼技術

當進行遠端跨程序服務呼叫時,需要把被傳輸的Java物件編碼為位元組陣列或者ByteBuffer物件。而當遠端服務讀取到ByteBuffer物件或者位元組陣列時,需要將其解碼為傳送時的Java物件。這被稱為Java物件編解碼技術。而我們常見得Java序列化僅僅是Java編解碼技術的一種,由於j