Netty的ChannelHandler大全

Netty的ChannelHandler大全

 

Handler是Netty的一個重要組件,涉及數據的各種業務處理操作以及數據包的編碼與解碼。本文對一些常見的ChannelHandler做簡要的概述和一些說明和使用場景,不做全面的詳細闡述。

1. ChannelInboundHandler接口

public interface ChannelInboundHandler extends ChannelHandler {
    //...略其他方法
    void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception;
    void channelReadComplete(ChannelHandlerContext ctx) throws Exception;
    @Override
    void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception;
}

Netty中所有的入站處理器都實現了ChannelInboundHandler接口,上面的部分源碼羅列了該接口最常被覆寫的方法。

2. ChannelInboundHandlerAdapter類

public class ChannelInboundHandlerAdapter extends ChannelHandlerAdapter implements ChannelInboundHandler {
    // ...略其他方法
    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        ctx.fireChannelRead(msg);
    }
}

ChannelInboundHandlerAdapter類是Netty爲開發者提供的默認入站處理器適配器實現類,該類實現了ChannelInboundHandler接口,開發者在自定義入站處理器時,只需通過繼承此類並複寫channelRead方法就可以完成自定義的入站處理邏輯。

public class AdapterTest extends ChannelInboundHandlerAdapter {
    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        ByteBuf buf=(ByteBuf)msg;
        byte[] bytes=new byte[buf.readableBytes()];
        buf.getBytes(0,bytes);
        System.out.println("入站數據:"+new String(bytes, CharsetUtil.UTF_8));
        super.channelRead(ctx, msg); //調用父類的channelRead方法(會默認添加)
    }
}

super.channelRead(ctx,msg) 調用父類的方法ctx.fireChannelRead(msg),觸發通道可讀事件,交由pipeline的下一個出站處理器處理。如果刪去這一調用,消息會被截斷,也即截停在這個出站處理器,下一入站處理器不會讀取到這個消息。

3. SimpleChannelInboundHandler抽象類

public abstract class SimpleChannelInboundHandler<I> extends ChannelInboundHandlerAdapter {
    //..略其他方法和屬性
    private final boolean autoRelease; //開啓自動釋放緩存
​
    protected SimpleChannelInboundHandler() {
        this(true);
    }
    protected SimpleChannelInboundHandler(boolean autoRelease) {
        matcher = TypeParameterMatcher.find(this, SimpleChannelInboundHandler.class, "I");
        this.autoRelease = autoRelease;
    }
​
    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        boolean release = true;
        try {
            if (acceptInboundMessage(msg)) {
                @SuppressWarnings("unchecked")
                I imsg = (I) msg;
                channelRead0(ctx, imsg);
            } else {
                release = false;
                ctx.fireChannelRead(msg);
            }
        } finally {
            if (autoRelease && release) {
                ReferenceCountUtil.release(msg);
            }
        }
    }
    protected abstract void channelRead0(ChannelHandlerContext ctx, I msg) throws Exception;
}
​

SimpleChannelInboundHandler(以下簡稱S)是一個泛型抽象類,繼承了ChannelInboundHandlerAdapter(以下簡稱A),也被常用作自定義的入站處理器的父類,但它與ChannelInboundHandlerAdapter有幾點不同:

  • S類可以指定消息泛型,支持處理泛型數據,而A類不支持

  • S類作爲父類時,需要覆寫channelRead0方法,A類作爲父類時,需要覆寫channelRead方法

  • S類默認是會自動釋放緩衝區內存的,當ByteBuf被釋放,消息將不會被進一步傳遞(與A類中不調用super方法類似)

因此,SimpleChannelInboundHandler常被用來做自動釋放,但也可以通過構造方法指定autoRelease=false關閉自動釋放功能。

4. ByteToMessageDecoder解碼器

編碼器首先也是一個入站處理器,ByteToMessageDecoders作爲解碼器的抽象父類,並不涉及具體的解碼實現,僅僅提供了一個解碼的流程框架。

public abstract class ByteToMessageDecoder extends ChannelInboundHandlerAdapter {
        protected abstract void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception;
    //..略其他方法屬性
}

經由ByteToMessageDecoder解碼後的消息,傳遞給下一站的不再是ByteBuf,該類會調用方法將緩衝區的引用-1,進而釋放緩衝區內存,解碼後得出的Java POJO(List<Object> out)作爲入站消息傳遞給下一個入站處理器。

5. ReplayingDecoder解碼器

public abstract class ReplayingDecoder<S> extends ByteToMessageDecoder {
    private S state; //狀態類型
    private int checkpoint = -1; //讀斷點指針位置
    //..略其他方法屬性
}

ReplayingDecoder抽象類(以下簡稱R類)繼承自ByteToMessageDecoder(以下簡稱B類),R類在內部定義了一個新的二進制緩衝區裝飾類,ReplayingDecoderBuffer,在緩衝區真正讀取數據之前,首先會進行長度判斷。除了長度判斷之外,ReplayingDecoder還可用來解決TCP粘包/半包問題,但是由於性能一般且並不是所有的ByteBuf操作都被ReplayingDecoderBuffer支持。所以這個類實際開發中使用的也不多。

6. MessageToMessageDecoder解碼器

public abstract class MessageToMessageDecoder<I> extends ChannelInboundHandlerAdapter {}

MessageToMessageDecoder繼承自ChannelInboundHandlerAdapter,可以將一個Java POJO對象解碼爲另外一個Java POJO對象,是個抽象泛型類,實現時需要指定入站消息類型。

7. FixenLengthFrameDecoder解碼器

public class FixedLengthFrameDecoder extends ByteToMessageDecoder {
    private final int frameLength;
    public FixedLengthFrameDecoder(int frameLength) {
        if (frameLength <= 0) {
            throw new IllegalArgumentException(
                    "frameLength must be a positive integer: " + frameLength);
        }
        this.frameLength = frameLength;
    }

固定長度數據包解碼器,適用於每個接受到的數據包的長度都是固定的。

8. LineBasedFrameDecoder解碼器

public class LineBasedFrameDecoder extends ByteToMessageDecoder {}

行分割數據包解碼器,適用於每個ByteBuf數據包使用換行符(\n)或者回車換行符(\r\n)作爲數據包的邊界分割。

9. DelimiterBasedFrameDecoder解碼器

public class DelimiterBasedFrameDecoder extends ByteToMessageDecoder {
   //略
   int maxFrameLength,   //解碼的數據包的最大長度
   boolean stripDelimiter,  //解碼後數據包是否去掉分隔符,一般選擇是
   ByteBuf delimiter     //分隔符
)

自定義分隔符數據包解碼器,與行分割數據包解碼器類似,但更通用,可以自己定義分隔符。

10. LegnthFieldFrameDecoder解碼器

public class LengthFieldBasedFrameDecoder extends ByteToMessageDecoder {
  int maxFrameLength,  //發送的數據包的最大長度 
  int lengthFieldOffset, //長度字段的偏移量,即長度字段位於數據包內部數組的起始下標 
  int legnthFieldLength, // 長度字段所佔的字節數,int爲4 short或char爲2 
  int lengthAdjustment, //矯正值計算公式:內容字段偏移-長度字段偏移-長度字段的字節(內容與長度間隔的長度)
  int initialBytesToStrip  //丟棄的起始字節數。
)

自定義長度數據包解碼器,長度靈活,可以自行設定,在一般的基於Header-Content協議的內容傳輸,都會使用這個解碼器進行解碼。該解碼器的5個重要屬性如代碼所示。

數據報構成 版本 長度 魔數 content
所佔字節 2字節 4字節 4字節 50字節

如上例子,lengthFileldOffset=2,lengthFiledLength=4,lengthAdujstment=4,initialBytesToStrip=10

11.ByteToMessageCodec編解碼器

編解碼器 也即編碼器跟解碼器都實現在了一個類中。

public abstract class ByteToMessageCodec<I> extends ChannelDuplexHandler { 
     //..略
    private final MessageToByteEncoder<I> encoder;
    private final ByteToMessageDecoder decoder ;
}

ByteToMessageCodec是一個抽象的泛型類,繼承時需要制定泛型I,I即編碼時的Java POJO對象的數據類型。

12. Http相關

  • HttpRequestEncoder 請求出站編碼器,用於HTTP客戶端

  • HttpRequestDeocoder 請求入解碼碼器,用於HTTP服務器

  • HttpResponseEncoder 響應出站編碼器,用戶HTTP服務器

  • HttpResponseDecoder 響應入站解碼器,用戶HTTP客戶端

  • HttpClientCodec 客戶端編解碼器

  • HttpServerCodec 服務端編解碼器

  • HttpObjectAggregator 消息聚合,將一個HttpMessage和跟隨它額度多個HttpContent聚合爲單個FullHttpRequest/FullHttpResponse

  • HttpContentDecompressor HTTP消息解壓

  • HttpContentComporessor HTTP消息壓縮

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章