居于netty的全双工,dubbo这样映射请求响应,每次请求都都会生成一个reqId,并把关系维护在FUTURES,在请求时把reqId放入请求帧中发送到服务端,服务端在响应的时候会把reqId放回到响应帧,并发送到客户端,客户端会根据该reqId从FUTURES获取。
请求
org.apache.dubbo.remoting.exchange.support.header.HeaderExchangeChannel#request(java.lang.Object, int)
org.apache.dubbo.remoting.exchange.support.DefaultFuture#DefaultFuture
@Override
public CompletableFuture<Object> request(Object request, int timeout) throws RemotingException {
if (closed) {
throw new RemotingException(this.getLocalAddress(), null, "Failed to send request " + request + ", cause: The channel " + this + " is closed!");
}
// create request. 请求对象
Request req = new Request();
req.setVersion(Version.getProtocolVersion());
req.setTwoWay(true);
/*
当交互协议是 dubbo 时
request === org.apache.dubbo.rpc.RpcInvocation
*/
req.setData(request); // 数据
DefaultFuture future = DefaultFuture.newFuture(channel, req, timeout); // !!!
try {
channel.send(req); // !!!
} catch (RemotingException e) {
future.cancel();
throw e;
}
return future;
}
响应
org.apache.dubbo.remoting.exchange.support.header.HeaderExchangeHandler#handleResponse
static void handleResponse(Channel channel, Response response) throws RemotingException {
if (response != null && !response.isHeartbeat()) {
DefaultFuture.received(channel, response); // !!!!
}
}
模拟代码
package cn.java.dubbo.demo.internal;
import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.common.Version;
import org.apache.dubbo.remoting.Channel;
import org.apache.dubbo.remoting.exchange.Request;
import org.apache.dubbo.remoting.exchange.Response;
import org.apache.dubbo.remoting.exchange.support.DefaultFuture;
import org.apache.dubbo.remoting.transport.ChannelDelegate;
import java.util.concurrent.CompletableFuture;
/**
*/
@Slf4j
public class RequestResponseMappingTest {
private static final int DEFAULT_TIMEOUT = 20 * 1000;
/**
* 通过请求Id来维护关系
*/
public static void main(String[] args) {
Channel channel = new ChannelDelegate();
// 请求对象
Request req = new Request();
req.setVersion(Version.getProtocolVersion());
req.setTwoWay(true);
DefaultFuture future = DefaultFuture.newFuture(channel, req, DEFAULT_TIMEOUT);
// 执行异步请求
new Thread(new Runnable() {
@Override
public void run() {
// 执行请求
try {
Thread.sleep(5 * 1000L);
} catch (InterruptedException e) {
e.printStackTrace();
}
// 接收
long reqId = req.getId(); // 请求Id,从消息帧里面提取reqId
Response response = new Response(reqId);
response.setResult("this is result.");
DefaultFuture.received(channel, response);
}
}).start();
// 等待结果
CompletableFuture<Object> responseFuture = future;
responseFuture.whenComplete((resp, ex) -> {
if (ex != null) {
log.error("异常", ex);
} else {
log.info("resp = {}", resp);
}
});
}
}