铿然架构 | 作者 / 铿然一叶 这是铿然架构的第 103 篇原创文章
相关阅读:
萌新快速成长之路
如何编写软件设计文档
JAVA编程思想(一)通过依赖注入增加扩展性
JAVA编程思想(二)如何面向接口编程
JAVA编程思想(三)去掉别扭的if,自注册策略模式优雅满足开闭原则
JAVA编程思想(四)Builder模式经典范式以及和工厂模式如何选?
Java编程思想(七)使用组合和继承的场景
JAVA基础(一)简单、透彻理解内部类和静态内部类
JAVA基础(二)内存优化-使用Java引用做缓存
JAVA基础(三)ClassLoader实现热加载
JAVA基础(四)枚举(enum)和常量定义,工厂类使用对比
JAVA基础(五)函数式接口-复用,解耦之利刃
Seata源码(一)初始化
Seata源码(二)事务基础对象
Seata源码(三)事务处理类结构和流程
Seata源码(四)全局锁GlobalLock
Seata源码(五)Seata数据库操作
Seata源码(六)Seata的undo日志操作
Seata源码(七)Seata事务故障处理
Seata源码(八)Seata事务生命周期hook
Seata源码(九)TCC核心类和处理逻辑
Seata源码(十)RM接收到请求后的调用过程
Seata源码(十一)TC接收到请求后的处理过程
Seata源码(十二)Session管理和持久化\
1. 概述
Seata消息框架底层基于Netty,核心能力包括消息发送,接收,派发,数据压缩/解压缩,序列化/反序列化,编/解码,消息合并,同步/异步,以及消息处理hook。
2. 类结构
整个消息框架的类结构如下:
类 | 描述 |
---|---|
AbstractNettyRemoting | 消息收发、派发抽象类 |
AbstractNettyRemotingClient | 客户端消息发送抽象类 |
AbstractNettyRemotingServer | 服务端消息发送抽象类 |
NettyRemotingServer | 服务端实现类 |
TmNettyRemotingClient | TM客户端 |
RmNettyRemotingClient | RM客户端 |
NettyClientBootstrap | netty客户端启动类 |
NettyServerBootstrap | netty服务端启动类 |
ClientHandler | netty消息客户端处理类 |
ServerHandler | netty消息服务端处理类 |
ProtocolV1Encoder | 消息编码类 |
ProtocolV1Decoder | 消息解码类 |
Compressor | 数据压缩/解压缩接口,可通过配置指定压缩算法,由对应子类实现压缩/解压缩 |
Serializer | 数据序列化/反序列化接口,可通过配置指定序列化算法,由对应子类实现序列化/反序列化 |
RemotingProcessor | 业务处理接口,接收消息后由AbstractNettyRemoting派发给消息对应的子类处理 |
RpcMessage | RPC消息,客户端和服务端交互的消息格式定义 |
MergedWarpMessage | 合并消息封装类 |
MergeResultMessage | 合并消息结果,合并消息请求的处理结果 |
MergedSendRunnable | 合并消息发送线程 |
MessageFuture | 异步消息封装类,用于发送异步消息,发送操作是异步的,但可以同步等待返回结果 |
RpcHook | 消息处理hook,可以在消息处理前后添加处理逻辑 |
StatusRpcHook | seata自带状态统计hook |
3.源码
3.1 RpcMessage
RpcMessage消息内容如下:
属性 | 描述 |
---|---|
id | id标识,id生成器生成 |
messageType | 消息类型 |
codec | 序列化算法 |
compressor | 压缩算法 |
headMap | 消息头信息,一个Map<String, String> |
body | 业务消息,会根据序列化算法和压缩算法进行处理 |
其中消息类型(messageType)如下:
消息类型 | 描述 |
---|---|
MSGTYPE_RESQUEST_SYNC | 同步请求消息,有应答 |
MSGTYPE_RESPONSE | 应答消息 |
MSGTYPE_RESQUEST_ONEWAY | oneway请求消息,没有应答 |
MSGTYPE_HEARTBEAT_REQUEST | 心跳请求 |
MSGTYPE_HEARTBEAT_RESPONSE | 心跳应答 |
3.2 消息编解码
3.2.1 编码
编码字段和顺序:
消息类型 | 描述 | 取值 | 字节长度 |
---|---|---|---|
MAGIC_CODE_BYTES | 魔法编码 | {(byte) 0xda, (byte) 0xda} | 2 |
VERSION | 版本 | 1 | 1 |
full length | 消息长度 | 计算得到 | 4 |
head length | rpc消息头长度 | 计算得到 | 2 |
messageType | 消息类型 | 实际消息类型 | 1 |
codec | 序列化算法 | 从配置获取 | 1 |
compressor | 压缩算法 | 从配置获取 | 1 |
id | 消息id | id生成器生成 | 4 |
head | 消息头信息 | 实际长度 | |
body | 消息体信息 | 实际长度 |
代码:
ProtocolV1Encoder.java
java
public void encode(ChannelHandlerContext ctx, Object msg, ByteBuf out) {
try {
if (msg instanceof RpcMessage) {
RpcMessage rpcMessage = (RpcMessage) msg;
int fullLength = ProtocolConstants.V1_HEAD_LENGTH;
int headLength = ProtocolConstants.V1_HEAD_LENGTH;
byte messageType = rpcMessage.getMessageType();
out.writeBytes(ProtocolConstants.MAGIC_CODE_BYTES);
out.writeByte(ProtocolConstants.VERSION);
// full Length(4B) and head length(2B) will fix in the end.
out.writerIndex(out.writerIndex() + 6);
out.writeByte(messageType);
out.writeByte(rpcMessage.getCodec());
out.writeByte(rpcMessage.getCompressor());
out.writeInt(rpcMessage.getId());
// direct write head with zero-copy
Map<String, String> headMap = rpcMessage.getHeadMap();
if (headMap != null && !headMap.isEmpty()) {
int headMapBytesLength = HeadMapSerializer.getInstance().encode(headMap, out);
headLength += headMapBytesLength;
fullLength += headMapBytesLength;
}
byte[] bodyBytes = null;
if (messageType != ProtocolConstants.MSGTYPE_HEARTBEAT_REQUEST
&& messageType != ProtocolConstants.MSGTYPE_HEARTBEAT_RESPONSE) {
// heartbeat has no body
Serializer serializer = EnhancedServiceLoader.load(Serializer.class, SerializerType.getByCode(rpcMessage.getCodec()).name());
bodyBytes = serializer.serialize(rpcMessage.getBody());
Compressor compressor = CompressorFactory.getCompressor(rpcMessage.getCompressor());
bodyBytes = compressor.compress(bodyBytes);
fullLength += bodyBytes.length;
}
if (bodyBytes != null) {
out.writeBytes(bodyBytes);
}
// fix fullLength and headLength
int writeIndex = out.writerIndex();
// skip magic code(2B) + version(1B)
out.writerIndex(writeIndex - fullLength + 3);
out.writeInt(fullLength);
out.writeShort(headLength);
out.writerIndex(writeIndex);
} else {
throw new UnsupportedOperationException("Not support this class:" + msg.getClass());
}
} catch (Throwable e) {
LOGGER.error("Encode request error!", e);
}
}
消息头编码,就是遍历map,取出key和value进行编码:
HeadMapSerializer.java
java
public int encode(Map<String, String> map, ByteBuf out) {
if (map == null || map.isEmpty() || out == null) {
return 0;
}
int start = out.writerIndex();
for (Map.Entry<String, String> entry : map.entrySet()) {
String key = entry.getKey();
String value = entry.getValue();
if (key != null) {
writeString(out, key);
writeString(out, value);
}
}
return out.writerIndex() - start;
}
3.2.2 解码
解码就是编码的反向操作。
ProtocolV1Decoder.java
java
public Object decodeFrame(ByteBuf frame) {
byte b0 = frame.readByte();
byte b1 = frame.readByte();
if (ProtocolConstants.MAGIC_CODE_BYTES[0] != b0
|| ProtocolConstants.MAGIC_CODE_BYTES[1] != b1) {
throw new IllegalArgumentException("Unknown magic code: " + b0 + ", " + b1);
}
byte version = frame.readByte();
// TODO check version compatible here
int fullLength = frame.readInt();
short headLength = frame.readShort();
byte messageType = frame.readByte();
byte codecType = frame.readByte();
byte compressorType = frame.readByte();
int requestId = frame.readInt();
RpcMessage rpcMessage = new RpcMessage();
rpcMessage.setCodec(codecType);
rpcMessage.setId(requestId);
rpcMessage.setCompressor(compressorType);
rpcMessage.setMessageType(messageType);
// direct read head with zero-copy
int headMapLength = headLength - ProtocolConstants.V1_HEAD_LENGTH;
if (headMapLength > 0) {
Map<String, String> map = HeadMapSerializer.getInstance().decode(frame, headMapLength);
rpcMessage.getHeadMap().putAll(map);
}
// read body
if (messageType == ProtocolConstants.MSGTYPE_HEARTBEAT_REQUEST) {
rpcMessage.setBody(HeartbeatMessage.PING);
} else if (messageType == ProtocolConstants.MSGTYPE_HEARTBEAT_RESPONSE) {
rpcMessage.setBody(HeartbeatMessage.PONG);
} else {
int bodyLength = fullLength - headLength;
if (bodyLength > 0) {
byte[] bs = new byte[bodyLength];
frame.readBytes(bs);
Compressor compressor = CompressorFactory.getCompressor(compressorType);
bs = compressor.decompress(bs);
Serializer serializer = EnhancedServiceLoader.load(Serializer.class, SerializerType.getByCode(rpcMessage.getCodec()).name());
rpcMessage.setBody(serializer.deserialize(bs));
}
}
return rpcMessage;
}
3.3 消息序列化
3.3.1 配置获取
ProtocolConstants.java
java
byte CONFIGURED_CODEC = SerializerType.getByName(ConfigurationFactory.getInstance()
.getConfig(ConfigurationKeys.SERIALIZE_FOR_RPC, SerializerType.SEATA.name())).getCode();
3.3.2 配置参数传入
构造rpc消息时传入:
AbstractNettyRemoting.java
java
protected RpcMessage buildRequestMessage(Object msg, byte messageType) {
RpcMessage rpcMessage = new RpcMessage();
rpcMessage.setId(getNextMessageId());
rpcMessage.setMessageType(messageType);
rpcMessage.setCodec(ProtocolConstants.CONFIGURED_CODEC);
rpcMessage.setCompressor(ProtocolConstants.CONFIGURED_COMPRESSOR);
rpcMessage.setBody(msg);
return rpcMessage;
}
3.3.3 创建序列化子类
通过EnhancedServiceLoader.load方法获取:
ProtocolV1Decoder.java和ProtocolV1Encoder.java
java
Serializer serializer = EnhancedServiceLoader.load(Serializer.class, SerializerType.getByCode(rpcMessage.getCodec()).name());
3.4 消息压缩
压缩算法通过配置transport.compressor获取,默认不需要压缩,压缩算法有gzip,zip,sevenz,bzip2,lz4,deflater。
3.4.1 配置获取
ProtocolConstants.java
java
byte CONFIGURED_COMPRESSOR = CompressorType.getByName(ConfigurationFactory.getInstance()
.getConfig(ConfigurationKeys.COMPRESSOR_FOR_RPC, CompressorType.NONE.name())).getCode();
3.4.2 参数传入
构造rpc消息时传入,同序列化参数。
3.4.3 创建压缩算法子类
调用工厂方法获取:
ProtocolV1Decoder.java和ProtocolV1Encoder.java
java
Compressor compressor = CompressorFactory.getCompressor(rpcMessage.getCompressor());
工厂方法,最终和序列化一样,调用EnhancedServiceLoader.load方法生成:
CompressorFactory.java
java
public static Compressor getCompressor(byte code) {
CompressorType type = CompressorType.getByCode(code);
return CollectionUtils.computeIfAbsent(COMPRESSOR_MAP, type,
key -> EnhancedServiceLoader.load(Compressor.class, type.name()));
}
3.5 消息接收处理
3.5.1 客户端消息处理编排
在NettyClientBootstrap中添加了编解码处理类和ClientHandler类:
NettyClientBootstrap.java
java
bootstrap.handler(
new ChannelInitializer<SocketChannel>() {
@Override
public void initChannel(SocketChannel ch) {
ChannelPipeline pipeline = ch.pipeline();
pipeline.addLast(
new IdleStateHandler(nettyClientConfig.getChannelMaxReadIdleSeconds(),
nettyClientConfig.getChannelMaxWriteIdleSeconds(),
nettyClientConfig.getChannelMaxAllIdleSeconds()))
.addLast(new ProtocolV1Decoder())
.addLast(new ProtocolV1Encoder());
if (channelHandlers != null) {
addChannelPipelineLast(ch, channelHandlers);
}
}
});
3.5.2 服务端消息处理编排
在NettyServerBootstrap中添加了编解码处理类和ServerHandler类:
NettyServerBootstrap.java
java
this.serverBootstrap.group(this.eventLoopGroupBoss, this.eventLoopGroupWorker)
.channel(NettyServerConfig.SERVER_CHANNEL_CLAZZ)
.option(ChannelOption.SO_BACKLOG, nettyServerConfig.getSoBackLogSize())
.option(ChannelOption.SO_REUSEADDR, true)
.childOption(ChannelOption.SO_KEEPALIVE, true)
.childOption(ChannelOption.TCP_NODELAY, true)
.childOption(ChannelOption.SO_SNDBUF, nettyServerConfig.getServerSocketSendBufSize())
.childOption(ChannelOption.SO_RCVBUF, nettyServerConfig.getServerSocketResvBufSize())
.childOption(ChannelOption.WRITE_BUFFER_WATER_MARK,
new WriteBufferWaterMark(nettyServerConfig.getWriteBufferLowWaterMark(),
nettyServerConfig.getWriteBufferHighWaterMark()))
.localAddress(new InetSocketAddress(listenPort))
.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
public void initChannel(SocketChannel ch) {
ch.pipeline().addLast(new IdleStateHandler(nettyServerConfig.getChannelMaxReadIdleSeconds(), 0, 0))
.addLast(new ProtocolV1Decoder())
.addLast(new ProtocolV1Encoder());
if (channelHandlers != null) {
addChannelPipelineLast(ch, channelHandlers);
}
}
});
3.5.3 客户端读消息
读消息时已经完成了解码,反序列化,解压缩:
ClientHandler.java
java
public void channelRead(final ChannelHandlerContext ctx, Object msg) throws Exception {
if (!(msg instanceof RpcMessage)) {
return;
}
// 这里开始派发消息
processMessage(ctx, (RpcMessage) msg);
}
3.5.4 服务端读消息
读消息时已经完成了解码,反序列化,解压缩:
ServerHandler.java
java
public void channelRead(final ChannelHandlerContext ctx, Object msg) throws Exception {
if (!(msg instanceof RpcMessage)) {
return;
}
// 这里开始派发消息
processMessage(ctx, (RpcMessage) msg);
}
3.6 消息派发
消息派发相关类结构如下:
采用通用的register & dispatch结构。
核心逻辑是先注册消息类型和RemotingProcessor子类的关系到缓存中,接收到消息后根据消息类型查找到对应的RemotingProcessor子类,将消息派发给子类处理。
注册逻辑摘选:
RmNettyRemotingClient.java
java
private void registerProcessor() {
// 1.registry rm client handle branch commit processor
RmBranchCommitProcessor rmBranchCommitProcessor = new RmBranchCommitProcessor(getTransactionMessageHandler(), this);
super.registerProcessor(MessageType.TYPE_BRANCH_COMMIT, rmBranchCommitProcessor, messageExecutor);
// 2.registry rm client handle branch commit processor
RmBranchRollbackProcessor rmBranchRollbackProcessor = new RmBranchRollbackProcessor(getTransactionMessageHandler(), this);
super.registerProcessor(MessageType.TYPE_BRANCH_ROLLBACK, rmBranchRollbackProcessor, messageExecutor);
// 3.registry rm handler undo log processor
RmUndoLogProcessor rmUndoLogProcessor = new RmUndoLogProcessor(getTransactionMessageHandler());
super.registerProcessor(MessageType.TYPE_RM_DELETE_UNDOLOG, rmUndoLogProcessor, messageExecutor);
// 4.registry TC response processor
ClientOnResponseProcessor onResponseProcessor =
new ClientOnResponseProcessor(mergeMsgMap, super.getFutures(), getTransactionMessageHandler());
super.registerProcessor(MessageType.TYPE_SEATA_MERGE_RESULT, onResponseProcessor, null);
super.registerProcessor(MessageType.TYPE_BRANCH_REGISTER_RESULT, onResponseProcessor, null);
super.registerProcessor(MessageType.TYPE_BRANCH_STATUS_REPORT_RESULT, onResponseProcessor, null);
super.registerProcessor(MessageType.TYPE_GLOBAL_LOCK_QUERY_RESULT, onResponseProcessor, null);
super.registerProcessor(MessageType.TYPE_REG_RM_RESULT, onResponseProcessor, null);
// 5.registry heartbeat message processor
ClientHeartbeatProcessor clientHeartbeatProcessor = new ClientHeartbeatProcessor();
super.registerProcessor(MessageType.TYPE_HEARTBEAT_MSG, clientHeartbeatProcessor, null);
}
派发逻辑:
AbstractNettyRemoting.java
java
protected void processMessage(ChannelHandlerContext ctx, RpcMessage rpcMessage) throws Exception {
if (LOGGER.isDebugEnabled()) {
LOGGER.debug(String.format("%s msgId:%s, body:%s", this, rpcMessage.getId(), rpcMessage.getBody()));
}
Object body = rpcMessage.getBody();
if (body instanceof MessageTypeAware) {
MessageTypeAware messageTypeAware = (MessageTypeAware) body;
// 查找RemotingProcessor实现类并调用
final Pair<RemotingProcessor, ExecutorService> pair = this.processorTable.get((int) messageTypeAware.getTypeCode());
if (pair != null) {
if (pair.getSecond() != null) {
try {
pair.getSecond().execute(() -> {
try {
pair.getFirst().process(ctx, rpcMessage);
} catch (Throwable th) {
LOGGER.error(FrameworkErrorCode.NetDispatch.getErrCode(), th.getMessage(), th);
} finally {
MDC.clear();
}
});
} catch (RejectedExecutionException e) {
LOGGER.error(FrameworkErrorCode.ThreadPoolFull.getErrCode(),
"thread pool is full, current max pool size is " + messageExecutor.getActiveCount());
if (allowDumpStack) {
String name = ManagementFactory.getRuntimeMXBean().getName();
String pid = name.split("@")[0];
int idx = new Random().nextInt(100);
try {
Runtime.getRuntime().exec("jstack " + pid + " >d:/" + idx + ".log");
} catch (IOException exx) {
LOGGER.error(exx.getMessage());
}
allowDumpStack = false;
}
}
} else {
try {
pair.getFirst().process(ctx, rpcMessage);
} catch (Throwable th) {
LOGGER.error(FrameworkErrorCode.NetDispatch.getErrCode(), th.getMessage(), th);
}
}
} else {
LOGGER.error("This message type [{}] has no processor.", messageTypeAware.getTypeCode());
}
} else {
LOGGER.error("This rpcMessage body[{}] is not MessageTypeAware type.", body);
}
}
3.7 消息合并处理
消息合并的目的是减少交互次数,提高性能。
3.7.1 合并消息结构
请求消息存储在MergedWarpMessage中,消息结构如下:
属性 | 描述 |
---|---|
msgIds | List,消息标识列表 |
msgs | List,消息列表,顺序和前面的消息标识列表对应 |
typeCode | 消息类型编码,固定值MessageType.TYPE_SEATA_MERGE |
应答消息存储在MergeResultMessage中,消息结构如下:
属性 | 描述 |
---|---|
msgs | AbstractResultMessage[],结果消息数组 |
typeCode | 消息类型编码,固定值MessageType.TYPE_SEATA_MERGE_RESULT |
3.7.2 合并消息处理
首先将消息放入basket(当客户端支持批量发送请求时才放入backet):
AbstractNettyRemotingClient.java
java
public Object sendSyncRequest(Object msg) throws TimeoutException {
String serverAddress = loadBalance(getTransactionServiceGroup(), msg);
int timeoutMillis = NettyClientConfig.getRpcRequestTimeout();
RpcMessage rpcMessage = buildRequestMessage(msg, ProtocolConstants.MSGTYPE_RESQUEST_SYNC);
// send batch message
// put message into basketMap, @see MergedSendRunnable
if (NettyClientConfig.isEnableClientBatchSendRequest()) {
// send batch message is sync request, needs to create messageFuture and put it in futures.
MessageFuture messageFuture = new MessageFuture();
messageFuture.setRequestMessage(rpcMessage);
messageFuture.setTimeout(timeoutMillis);
futures.put(rpcMessage.getId(), messageFuture);
// put message into basketMap
BlockingQueue<RpcMessage> basket = CollectionUtils.computeIfAbsent(basketMap, serverAddress,
key -> new LinkedBlockingQueue<>());
if (!basket.offer(rpcMessage)) {
LOGGER.error("put message into basketMap offer failed, serverAddress:{},rpcMessage:{}",
serverAddress, rpcMessage);
return null;
}
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("offer message: {}", rpcMessage.getBody());
}
if (!isSending) {
synchronized (mergeLock) {
mergeLock.notifyAll();
}
}
try {
// 异步获取消息应答
return messageFuture.get(timeoutMillis, TimeUnit.MILLISECONDS);
} catch (Exception exx) {
LOGGER.error("wait response error:{},ip:{},request:{}",
exx.getMessage(), serverAddress, rpcMessage.getBody());
if (exx instanceof TimeoutException) {
throw (TimeoutException) exx;
} else {
throw new RuntimeException(exx);
}
}
} else {
Channel channel = clientChannelManager.acquireChannel(serverAddress);
return super.sendSync(channel, rpcMessage, timeoutMillis);
}
}
消息合并后发送,通过线程异步处理:
MergedSendRunnable.java
java
basketMap.forEach((address, basket) -> {
if (basket.isEmpty()) {
return;
}
MergedWarpMessage mergeMessage = new MergedWarpMessage();
while (!basket.isEmpty()) {
RpcMessage msg = basket.poll();
mergeMessage.msgs.add((AbstractMessage) msg.getBody());
mergeMessage.msgIds.add(msg.getId());
}
if (mergeMessage.msgIds.size() > 1) {
printMergeMessageLog(mergeMessage);
}
Channel sendChannel = null;
try {
// send batch message is sync request, but there is no need to get the return value.
// Since the messageFuture has been created before the message is placed in basketMap,
// the return value will be obtained in ClientOnResponseProcessor.
sendChannel = clientChannelManager.acquireChannel(address);
AbstractNettyRemotingClient.this.sendAsyncRequest(sendChannel, mergeMessage);
}
服务端接收到合并消息的处理,并将合并消息的处理结果也合并后返回:
ServerOnRequestProcessor.java的onRequestMessage方法内
java
if (message instanceof MergedWarpMessage) {
AbstractResultMessage[] results = new AbstractResultMessage[((MergedWarpMessage) message).msgs.size()];
for (int i = 0; i < results.length; i++) {
final AbstractMessage subMessage = ((MergedWarpMessage) message).msgs.get(i);
// 这里的onRequest是DefaultCoordinator类的方法
results[i] = transactionMessageHandler.onRequest(subMessage, rpcContext);
}
MergeResultMessage resultMessage = new MergeResultMessage();
resultMessage.setMsgs(results);
remotingServer.sendAsyncResponse(rpcMessage, ctx.channel(), resultMessage);
}
客户端收到合并请求处理结果的处理:
ClientOnResponseProcessor.java
java
public void process(ChannelHandlerContext ctx, RpcMessage rpcMessage) throws Exception {
if (rpcMessage.getBody() instanceof MergeResultMessage) {
MergeResultMessage results = (MergeResultMessage) rpcMessage.getBody();
MergedWarpMessage mergeMessage = (MergedWarpMessage) mergeMsgMap.remove(rpcMessage.getId());
for (int i = 0; i < mergeMessage.msgs.size(); i++) {
int msgId = mergeMessage.msgIds.get(i);
MessageFuture future = futures.remove(msgId);
if (future == null) {
if (LOGGER.isInfoEnabled()) {
LOGGER.info("msg: {} is not found in futures.", msgId);
}
} else {
future.setResultMessage(results.getMsgs()[i]);
}
}
}
3.8 消息异步处理
消息异步处理目的是提高效率。
服务端接收到请求后处理结果是异步发送的,而客户端要同步等待这个异步结果,为了实现这个目的,通过MessageFuture类来封装消息进行处理,其思路是利用CompletableFuture的能力,处理如下:
1.在发送请求后调用其get方法在客户端同步等待。
AbstractNettyRemotingClient.java的sendSyncRequest(Object msg)方法内:
java
try {
// 异步获取消息应答
return messageFuture.get(timeoutMillis, TimeUnit.MILLISECONDS);
}
2.服务端处理后,异步发送结果。
ServerOnRequestProcessor.java的onRequestMessage(ChannelHandlerContext ctx, RpcMessage rpcMessage)方法,结果是异步返回的:
java
remotingServer.sendAsyncResponse(rpcMessage, ctx.channel(), resultMessage);
remotingServer.sendAsyncResponse(rpcMessage, ctx.channel(), result);
3.客户端收到异步应答后,通过其complete方法设置应答消息并唤醒get方法。
java
public void process(ChannelHandlerContext ctx, RpcMessage rpcMessage) throws Exception {
......
MessageFuture future = futures.remove(msgId);
if (future == null) {
if (LOGGER.isInfoEnabled()) {
LOGGER.info("msg: {} is not found in futures.", msgId);
}
} else {
// 唤醒第1步中的messageFuture.get(timeoutMillis, TimeUnit.MILLISECONDS)
future.setResultMessage(results.getMsgs()[i]);
}
}
} else {
MessageFuture messageFuture = futures.remove(rpcMessage.getId());
if (messageFuture != null) {
// 唤醒第1步中的messageFuture.get(timeoutMillis, TimeUnit.MILLISECONDS)方法
messageFuture.setResultMessage(rpcMessage.getBody());
}
......
}
3.9 RpcHook
RpcHook提供了扩展能力,使得可以在消息发送前后做定制处理。
3.9.1 RpcHook子类加载
AbstractNettyRemoting.java
java
protected final List<RpcHook> rpcHooks = EnhancedServiceLoader.loadAll(RpcHook.class);
3.9.2 RpcHook子类调用
AbstractNettyRemoting.java
同步消息调用点(before和after方法都调用):
java
protected Object sendSync(Channel channel, RpcMessage rpcMessage, long timeoutMillis) throws TimeoutException {
.....
doBeforeRpcHooks(remoteAddr, rpcMessage);
......
try {
Object result = messageFuture.get(timeoutMillis, TimeUnit.MILLISECONDS);
doAfterRpcHooks(remoteAddr, rpcMessage, result);
return result;
}
异步消息调用点(只调用doBeforeRpcHooks方法):
java
protected void sendAsync(Channel channel, RpcMessage rpcMessage) {
......
doBeforeRpcHooks(ChannelUtil.getAddressFromChannel(channel), rpcMessage);
......
}
遍历调用:
java
protected void doBeforeRpcHooks(String remoteAddr, RpcMessage request) {
for (RpcHook rpcHook: rpcHooks) {
rpcHook.doBeforeRequest(remoteAddr, request);
}
}
protected void doAfterRpcHooks(String remoteAddr, RpcMessage request, Object response) {
for (RpcHook rpcHook: rpcHooks) {
rpcHook.doAfterResponse(remoteAddr, request, response);
}
}