在 dubbo:// 协议的调用,一共分成三种:
sync 同步调用
async 异步调用
oneway 单向调用
前两种比较好理解,都是基于 Request Response 模型,差异点在异步调用,服务消费者不阻塞等待结果,而是通过回调的方式,处理服务提供者返回的结果。
最后一种,基于 Message 模型,发起调用,而不关注等待和关注执行结果。
因此,从性能上:oneway > async > sync 。
调用 DubboInvoker#invoke(Invocation) 方法,调用服务。代码如下:
protected Result doInvoke(final Invocation invocation) {
RpcInvocation inv = (RpcInvocation) invocation;
// 获得方法名
final String methodName = RpcUtils.getMethodName(invocation);
// 获得 `path`( 服务名 ),`version`
inv.setAttachment(Constants.PATH_KEY, getUrl().getPath());
inv.setAttachment(Constants.VERSION_KEY, version);
// 获得 ExchangeClient 对象
ExchangeClient currentClient;
if (clients.length == 1) {
currentClient = clients[0];
} else {
currentClient = clients[index.getAndIncrement() % clients.length];
}
// 远程调用
try {
// 获得是否异步调用
boolean isAsync = RpcUtils.isAsync(getUrl(), invocation);
// 获得是否单向调用
boolean isOneway = RpcUtils.isOneway(getUrl(), invocation);
// 获得超时时间
int timeout = getUrl().getMethodParameter(methodName, Constants.TIMEOUT_KEY, Constants.DEFAULT_TIMEOUT);
// 单向调用
if (isOneway) {
boolean isSent = getUrl().getMethodParameter(methodName, Constants.SENT_KEY, false);
currentClient.send(inv, isSent);
RpcContext.getContext().setFuture(null);
return new RpcResult();
// 异步调用
} else if (isAsync) {
ResponseFuture future = currentClient.request(inv, timeout);
RpcContext.getContext().setFuture(new FutureAdapter
在 DubboProtocol 类中,实现了自己的 ExchangeHandler 对象,处理请求、消息、连接、断开连接等事件。对于服务消费者的远程调用,通过 #reply(ExchangeChannel channel, Object message) 和 #reply(Channel channel, Object message) 方法来处理。
reoly
public Object reply(ExchangeChannel channel, Object message) throws RemotingException {
if (message instanceof Invocation) {
Invocation inv = (Invocation) message;
// 获得请求对应的 Invoker 对象
Invoker> invoker = getInvoker(channel, inv);
// 如果是callback 需要处理高版本调用低版本的问题
// need to consider backward-compatibility if it's a callback
if (Boolean.TRUE.toString().equals(inv.getAttachments().get(IS_CALLBACK_SERVICE_INVOKE))) {
String methodsStr = invoker.getUrl().getParameters().get("methods");
boolean hasMethod = false;
if (methodsStr == null || !methodsStr.contains(",")) {
hasMethod = inv.getMethodName().equals(methodsStr);
} else {
String[] methods = methodsStr.split(",");
for (String method : methods) {
if (inv.getMethodName().equals(method)) {
hasMethod = true;
break;
}
}
}
if (!hasMethod) {
logger.warn(new IllegalStateException("The methodName " + inv.getMethodName() + " not found in callback service interface ,invoke will be ignored. please update the api interface. url is:" + invoker.getUrl()) + " ,invocation is :" + inv);
return null;
}
}
// 设置调用方的地址
RpcContext.getContext().setRemoteAddress(channel.getRemoteAddress());
// 执行调用
return invoker.invoke(inv);
}
throw new RemotingException(channel, message.getClass().getName() + ": " + message
+ ", channel: consumer: " + channel.getRemoteAddress() + " --> provider: " + channel.getLocalAddress());
}
getInvoker(channel, invocation) 方法,获得请求对应的 Invoker 对象。代码如下:
/**
* 获得请求对应的 Invoker 对象
*
* @param channel 通道
* @param inv Invocation
* @return Invoker 对象
* @throws RemotingException 当发生异常时
*/
Invoker> getInvoker(Channel channel, Invocation inv) throws RemotingException {
boolean isCallBackServiceInvoke;
boolean isStubServiceInvoke;
int port = channel.getLocalAddress().getPort();
String path = inv.getAttachments().get(Constants.PATH_KEY);
// TODO 【8005 sub】
// if it's callback service on client side
isStubServiceInvoke = Boolean.TRUE.toString().equals(inv.getAttachments().get(Constants.STUB_EVENT_KEY));
if (isStubServiceInvoke) {
port = channel.getRemoteAddress().getPort();
}
// 如果是参数回调,获得真正的服务名 `path` 。
// callback
isCallBackServiceInvoke = isClientSide(channel) && !isStubServiceInvoke;
if (isCallBackServiceInvoke) {
path = inv.getAttachments().get(Constants.PATH_KEY) + "." + inv.getAttachments().get(Constants.CALLBACK_SERVICE_KEY);
inv.getAttachments().put(IS_CALLBACK_SERVICE_INVOKE, Boolean.TRUE.toString());
}
// 获得服务建
String serviceKey = serviceKey(port, path, inv.getAttachments().get(Constants.VERSION_KEY), inv.getAttachments().get(Constants.GROUP_KEY));
// 获得 Exporter 对象
DubboExporter> exporter = (DubboExporter>) exporterMap.get(serviceKey);
// 获得 Invoker 对象
if (exporter == null) {
throw new RemotingException(channel, "Not found exported service: " + serviceKey + " in " + exporterMap.keySet() + ", may be version or group mismatch " + ", channel: consumer: " + channel.getRemoteAddress() + " --> provider: " + channel.getLocalAddress() + ", message:" + inv);
}
return exporter.getInvoker();
}