code-learning/netty/57-Netty 源码解析-Codec 之 ByteToMessageCodec.md

5.2 KiB
Raw Permalink Blame History

精尽 Netty 源码解析 —— Codec 之 ByteToMessageCodec

1. 概述

本文,我们来分享 ByteToMessageCodec 部分的内容。

在网络通信中,编解码是成对出现的,所以 Netty 提供了 ByteToMessageCodec 类,支持 Encoder 和 Decoder 两个功能。

2. ByteToMessageCodec

io.netty.handler.codec.ByteToMessageCodec ,继承 ChannelDuplexHandler 类,通过组合 MessageToByteEncoder 和 ByteToMessageDecoder 的功能,从而实现编解码的 Codec 抽象类

2.1 构造方法

public abstract class ByteToMessageCodec<I> extends ChannelDuplexHandler {

    /**
     * 类型匹配器
     */
    private final TypeParameterMatcher outboundMsgMatcher;
    /**
     * Encoder 对象
     */
    private final MessageToByteEncoder<I> encoder;
    /**
     * Decoder 对象
     */
    private final ByteToMessageDecoder decoder = new ByteToMessageDecoder() {
    
        @Override
        public void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {
            ByteToMessageCodec.this.decode(ctx, in, out);
        }
    
        @Override
        protected void decodeLast(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {
            ByteToMessageCodec.this.decodeLast(ctx, in, out);
        }
    
    };
    
    protected ByteToMessageCodec() {
        this(true);
    }
    
    protected ByteToMessageCodec(Class<? extends I> outboundMessageType) {
        this(outboundMessageType, true);
    }
    
    protected ByteToMessageCodec(boolean preferDirect) {
        // 禁止共享
        ensureNotSharable();
        // <1> 获得 matcher
        outboundMsgMatcher = TypeParameterMatcher.find(this, ByteToMessageCodec.class, "I");
        // 创建 Encoder 对象
        encoder = new Encoder(preferDirect);
    }
    
    protected ByteToMessageCodec(Class<? extends I> outboundMessageType, boolean preferDirect) {
        // 禁止共享
        ensureNotSharable();
        // <2> 获得 matcher
        outboundMsgMatcher = TypeParameterMatcher.get(outboundMessageType);
        // 创建 Encoder 对象
        encoder = new Encoder(preferDirect);
    }
    
    // ... 省略其他无关代码
    
    private final class Encoder extends MessageToByteEncoder<I> {

        Encoder(boolean preferDirect) {
            super(preferDirect);
        }

        @Override
        public boolean acceptOutboundMessage(Object msg) throws Exception {
            return ByteToMessageCodec.this.acceptOutboundMessage(msg);
        }

        @Override
        protected void encode(ChannelHandlerContext ctx, I msg, ByteBuf out) throws Exception {
            ByteToMessageCodec.this.encode(ctx, msg, out);
        }

    }
    
}
  • MessageToByteEncoder 部分
    • encoder 属性Encoder 对象,继承自 MessageToByteEncoder 抽象类。只能在构造方法中创建,因为他依赖构造方法的 preferDirect 方法参数,所以不能像 decoder 直接使用属性赋值。
    • outboundMsgMatcher 属性,类型匹配器,在 <1> / <2> 处初始化。
  • ByteToMessageDecoder 部分
    • decoder 属性Decoder 对象,继承自 ByteToMessageDecoder 抽象类。

2.2 ChannelHandler 相关方法

@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
    decoder.channelRead(ctx, msg);
}

@Override
public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception {
    encoder.write(ctx, msg, promise);
}

@Override
public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
    decoder.channelReadComplete(ctx);
}

@Override
public void channelInactive(ChannelHandlerContext ctx) throws Exception {
    decoder.channelInactive(ctx);
}

@Override
public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
    try {
        decoder.handlerAdded(ctx);
    } finally {
        encoder.handlerAdded(ctx);
    }
}

@Override
public void handlerRemoved(ChannelHandlerContext ctx) throws Exception {
    try {
        decoder.handlerRemoved(ctx);
    } finally {
        encoder.handlerRemoved(ctx);
    }
}

2.3 MessageToByteEncoder 相关方法

/**
 * @see ByteToMessageDecoder#decode(ChannelHandlerContext, ByteBuf, List)
 */
protected abstract void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception;

/**
 * @see ByteToMessageDecoder#decodeLast(ChannelHandlerContext, ByteBuf, List)
 */
protected void decodeLast(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {
    if (in.isReadable()) {
        // Only call decode() if there is something left in the buffer to decode.
        // See https://github.com/netty/netty/issues/4386
        decode(ctx, in, out);
    }
}

2.4 MessageToByteEncoder 相关方法

/**
 * Returns {@code true} if and only if the specified message can be encoded by this codec.
 *
 * @param msg the message
 */
public boolean acceptOutboundMessage(Object msg) throws Exception {
    return outboundMsgMatcher.match(msg);
}

/**
 * @see MessageToByteEncoder#encode(ChannelHandlerContext, Object, ByteBuf)
 */
protected abstract void encode(ChannelHandlerContext ctx, I msg, ByteBuf out) throws Exception;

666. 彩蛋

小小的水文一篇,嘿嘿。