1 概述
如下图所示,业务层与Netty客户端之间用RemotingCommand
进行交互,即业务层调用Netty发送消息时,会将消息封装在RemotingCommand
对象里面,而Netty接收到外部消息的时候会给业务层返回RemotingCommand
的对象实例。
Netty与外部世界通过字节流进行传输。Netty在发送消息的时候,对RemotingCommand进行编码(对象–>字节流);在接收到外部消息的时候会对字节流进行解码(字节流–>对象)。
业务层与Netty之间交互方式的伪代码:
- 准备消息头,CommandCustomHeader,“通信协议”,不同场景下,例如发送消息和请求消息,携带的信息不一样。约定好的协议。
- 准备消息体,body
- 使用消息头和消息体创建RemotingCommand对象
- 调用Netty进行发送
----经过业务层构建处理的消息体Header/body----
header = ...;
body = ...;
----准备RemotingCommand----
remotingCommand = new RemotingCommand();
remotingCommand.setCustomerHeader(header);
remotingCommand.setBody(body);
----调用Netty发送RemotingCommand----
Netty.send(remotingCommand);
2 编码
Netty会用NettyEncoder
对对象进行编码。该类的源码如下,它继承了Netty中的MessageToByteEncoder
。覆写了encode()
方法。它的泛型变量为RemotingCommand
表示它只处理传递过来的RemotingCommand
的对象。
它里面的编码逻辑,首先对消息头进行编码,然后编码消息体。消息体其实已经是字节流了,直接写入ByteBuf中即可。而需要对消息头进行编码。对消息头编码时调用的是RemotingCommand
的encodeHeader()
方法。
public class NettyEncoder extends MessageToByteEncoder<RemotingCommand> {
private static final InternalLogger log = InternalLoggerFactory.getLogger(RemotingHelper.ROCKETMQ_REMOTING);
@Override
public void encode(ChannelHandlerContext ctx, RemotingCommand remotingCommand, ByteBuf out)
throws Exception {
try {
// 编码头部
ByteBuffer header = remotingCommand.encodeHeader();
out.writeBytes(header);
// 之前已经编码好了,即已经是二进制了
byte[] body = remotingCommand.getBody();
if (body != null) {
out.writeBytes(body);
}
} catch (Exception e) {
log.error("encode exception, " + RemotingHelper