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

180 lines
5.2 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 精尽 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 相关方法
```Java
/**
* @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. 彩蛋
小小的水文一篇,嘿嘿。