一、前沿
前面分析了 Dubbo SPI、provider服务导出、consumer服务引用的源码,接下来就是分析服务调用的过程了,在学习服务调用之前,最好先学习 集群容错 模块,它包含四个部分,分别是 服务目录 Directory、服务路由 Router、集群 Cluster 和 负载均衡 LoadBalance
Dubbo 服务调用过程比较复杂,总体上来说包含如下步骤:
发送请求 -> 编解码 -> 服务降级 -> 过滤器链处理 -> 序列化 -> 线程派发 -> 响应请求 -> 结果编码 -> 结果解码
本文将着重讲解 发送请求、编解码、线程派发和响应请求部分代码,至于服务降级、过滤器链和序列化部分代码后续再讲解
二、服务调用过程
我们先通过下面一张图了解 Dubbo 服务调用过程,如图:
从上述图中我们可以看出调用过程:
1)、consumer 通过代理对象 Proxy 发起远程调用,接着通过网络客户端 Client 将编码后的请求发送给 provider,也就是 Server 端
2)、provider 收到请求后先对数据包解码,然后将解码后的请求发送至分发器 Dispatcher
3)、Dispatcher 分发器将请求派发到指定的线程池上,最后由线程池调用具体的服务
图中的过程虽然没有描述provider响应数据的发送与consumer接收数据的过程,但是后面会通过源码来详细分析
三、服务调用源码
3.1 consumer调用方式
Dubbo 支持同步和异步两种调用方式,其中异步调用还可细分为“有返回值”的异步调用和“无返回值”的异步调用。所谓“无返回值”异步调用是指consumer只管调用,不需要关心调用结果,此时 Dubbo 会直接返回一个空的 AsyncRpcResult。若要使用异步特性,需要consumer方手动进行配置。默认情况下,Dubbo 使用同步调用方式
我们以 dubbo-demo 中的 consumer debug运行调试代码查看服务调用过程,如下图:
上述debug调用栈中可以看出调用过程,main(Application) -> sayHello(proxy0)-> invoke(InvokerInvocationHandler),在 consumer服务引用 中我们知道 proxy0.class 代理类的代码如下:
package org.apache.dubbo.common.bytecode;
import com.alibaba.dubbo.rpc.service.EchoService;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import org.apache.dubbo.demo.DemoService;
public class proxy0
implements ClassGenerator.DC, EchoService, DemoService
{
public static Method[] methods;
private InvocationHandler handler;
public String sayHello(String paramString)
{
// 将运行时参数存储到数组中
Object[] arrayOfObject = new Object[1];
arrayOfObject[0] = paramString;
// 调用 InvocationHandler 实现类的 invoke 方法得到调用结果
Object localObject = this.handler.invoke(this, methods[0], arrayOfObject);
// 返回调用结果
return (String)localObject;
}
// 回声测试方法
public Object $echo(Object paramObject)
{
Object[] arrayOfObject = new Object[1];
arrayOfObject[0] = paramObject;
Object localObject = this.handler.invoke(this, methods[1], arrayOfObject);
return (Object)localObject;
}
public proxy0()
{
}
public proxy0(InvocationHandler paramInvocationHandler)
{
this.handler = paramInvocationHandler;
}
}
proxy0 实现了 DemoService,实现了 sayHello 方法具体业务,DemoService 调用 sayHello 的时会先调用了 proxy0(DemoService的实现类) 的 sayHello,而 sayHello 则会调用 InvokerInvocationHandler 的 invoke 方法
接下来看 InvokerInvocationHandler 源码,如下:
package org.apache.dubbo.rpc.proxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import org.apache.dubbo.common.logger.Logger;
import org.apache.dubbo.common.logger.LoggerFactory;
import org.apache.dubbo.rpc.Invoker;
import org.apache.dubbo.rpc.RpcInvocation;
/**
* InvokerHandler
*/
public class InvokerInvocationHandler implements InvocationHandler {
private static final Logger logger = LoggerFactory.getLogger(InvokerInvocationHandler.class);
private final Invoker<?> invoker;
public InvokerInvocationHandler(Invoker<?> handler) {
this.invoker = handler;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 获取方法名
String methodName = method.getName();
// 获取方法参数
Class<?>[] parameterTypes = method.getParameterTypes();
if (method.getDeclaringClass() == Object.class) {
// 定义在 Object 类中的方法(未被子类重写),比如 wait/notify等,直接调用
return method.invoke(invoker, args);
}
// 如果 toString、hashCode 和 equals 等方法被子类重写了,这里也直接调用
if ("toString".equals(methodName) && parameterTypes.length == 0) {
return invoker.toString();
}
if ("hashCode".equals(methodName) && parameterTypes.length == 0) {
return invoker.hashCode();
}
if ("equals".equals(methodName) && parameterTypes.length == 1) {
return invoker.equals(args[0]);
}
// 将 method 和 args 封装到 RpcInvocation 中,调用 MockClusterInvoker 的 invoke方法
// 最后调用 recreate 方法返回结果数据
return invoker.invoke(new RpcInvocation(method, args)).recreate();
}
}
InvokerInvocationHandler 的 invoke 方法中逻辑很简单,注释已经说得很明白,这里就不在说了
下面我们看最终调用的 Invoker 的 invoke 方法,代码如下:
// 1、MockClusterInvoker 的 invoke 方法
@Override
public Result invoke(Invocation invocation) throws RpcException {
Result result = null;
// 获取 mock 配置
String value = directory.getUrl().getMethodParameter(invocation.getMethodName(), MOCK_KEY, Boolean.FALSE.toString()).trim();
if (value.length() == 0 || "false".equalsIgnoreCase(value)) {
//no mock
// 没有 mock 配置 或者 mock 为 false,直接调用 AbstractClusterInvoker 的 invoke 方法
result = this.invoker.invoke(invocation);
} else if (value.startsWith("force")) {
if (logger.isWarnEnabled()) {
logger.warn("force-mock: " + invocation.getMethodName() + " force-mock enabled , url : " + directory.getUrl());
}
//force:direct mock
// force:xxx 直接执行 mock 逻辑,不发起远程调用,这里就是服务降级策略
result = doMockInvoke(invocation, null);
} else {
//fail-mock
// consumer 调用失败后,再执行 mock 逻辑,不抛出异常
try {
result = this.invoker.invoke(invocation);
//fix:#4585
if(result.getException() != null && result.getException() instanceof RpcException){
RpcException rpcException= (RpcException)result.getException();
if(rpcException.isBiz()){
throw rpcException;
}else {
// 调用失败,执行 mock 逻辑,即服务降级
result = doMockInvoke(invocation, rpcException);
}
}
} catch (RpcException e) {
if (e.isBiz()) {
throw e;
}
if (logger.isWarnEnabled()) {
logger.warn("fail-mock: " + invocation.getMethodName() + " fail-mock enabled , url : " + directory.getUrl(), e);
}
result = doMockInvoke(invocation, e);
}
}
return result;
}
// 2、AbstractClusterInvoker 的 invoke 方法
@Override
public Result invoke(final Invocation invocation) throws RpcException {
// 校验 Invoker 是否销毁了
checkWhetherDestroyed();
// binding attachments into invocation.
// 将 RpcContext 中的 attachments 参数绑定到 RpcInvocation 中
Map<String, String> contextAttachments = RpcContext.getContext().getAttachments();
if (contextAttachments != null && contextAttachments.size() != 0) {
((RpcInvocation) invocation).addAttachments(contextAttachments);
}
// 获取 Invoker 列表
List<Invoker<T>> invokers = list(invocation);
// 初始化负载均衡策略,RandomLoadBalance 为默认的负载均衡策略
// invokers 不为空时,则取第一个 invoker 的 url 中 loadbalance 参数设置的负载均衡策略
LoadBalance loadbalance = initLoadBalance(invokers, invocation);
// 如果请求是异步的,需要设置 id 参数到 RpcInvocation 的 Attachment 中
RpcUtils.attachInvocationIdIfAsync(getUrl(), invocation);
// 调用具体的 Invoker 实现类,dubbo 中默认是 FailoverClusterInvoker,故这里调用 FailoverClusterInvoker 的 doInvoke 方法
return doInvoke(invocation, invokers, loadbalance);
}
FailoverClusterInvoker 的 doInvoke 方法在 dubbo集群 中讲解了,这里直接从 FailoverClusterInvoker 的 doInvoke 方法调用目标 Invoker 的 invoke 方法讲起,debug调试栈如下图所示:
栈信息内容如下:
doInvoke:96, DubboInvoker (org.apache.dubbo.rpc.protocol.dubbo)
invoke:155, AbstractInvoker (org.apache.dubbo.rpc.protocol)
invoke:52, AsyncToSyncInvoker (org.apache.dubbo.rpc.protocol)
invoke:92, MonitorFilter (org.apache.dubbo.monitor.support)
invoke:82, ProtocolFilterWrapper$1 (org.apache.dubbo.rpc.protocol)
invoke:54, FutureFilter (org.apache.dubbo.rpc.protocol.dubbo.filter)
invoke:82, ProtocolFilterWrapper$1 (org.apache.dubbo.rpc.protocol)
invoke:58, ConsumerContextFilter (org.apache.dubbo.rpc.filter)
invoke:82, ProtocolFilterWrapper$1 (org.apache.dubbo.rpc.protocol)
invoke:157, ProtocolFilterWrapper$CallbackRegistrationInvoker (org.apache.dubbo.rpc.protocol)
invoke:78, ListenerInvokerWrapper (org.apache.dubbo.rpc.listener)
invoke:56, InvokerWrapper (org.apache.dubbo.rpc.protocol)
doInvoke:91, FailoverClusterInvoker (org.apache.dubbo.rpc.cluster.support)
invoke:256, AbstractClusterInvoker (org.apache.dubbo.rpc.cluster.support)
invoke:81, MockClusterInvoker (org.apache.dubbo.rpc.cluster.support.wrapper)
invoke:61, InvokerInvocationHandler (org.apache.dubbo.rpc.proxy)
sayHello:-1, proxy0 (org.apache.dubbo.common.bytecode)
main:27, Application (org.apache.dubbo.demo.consumer)
调用目标 Invoker 的 invoke 方法过程源码如下:
// 1、InvokerWrapper 的 invoke 方法
@Override
public Result invoke(Invocation invocation) throws RpcException {
// 调用 ListenerInvokerWrapper 的 invoke 方法
return invoker.invoke(invocation);
}
// 2、ListenerInvokerWrapper 的 invoke
@Override
public Result invoke(Invocation invocation) throws RpcException {
// 调用 ProtocolFilterWrapper 的回调 CallbackRegistrationInvoker 中的 invoke 方法
return invoker.invoke(invocation);
}
/**
* Register callback for each filter may be better, just like {@link java.util.concurrent.CompletionStage}, each callback
* registration generates a new CompletionStage whose status is determined by the original CompletionStage.
*
* If bridging status between filters is proved to not has significant performance drop, consider revert to the following commit:
* https://github.com/apache/dubbo/pull/4127
*/
static class CallbackRegistrationInvoker<T> implements Invoker<T> {
private final Invoker<T> filterInvoker;
private final List<Filter> filters;
public CallbackRegistrationInvoker(Invoker<T> filterInvoker, List<Filter> filters) {
this.filterInvoker = filterInvoker;
this.filters = filters;
}
// 3、ProtocolFilterWrapper 的内部类 CallbackRegistrationInvoker 中的 invoke 方法
@Override
public Result invoke(Invocation invocation) throws RpcException {
// 调用 ProtocolFilterWrapper 的 lastInvoker 中的 invoke 方法
Result asyncResult = filterInvoker.invoke(invocation);
asyncResult = asyncResult.whenCompleteWithContext((r, t) -> {
for (int i = filters.size() - 1; i >= 0; i--) {
Filter filter = filters.get(i);
// onResponse callback
if (filter instanceof ListenableFilter) {
Filter.Listener listener = ((ListenableFilter) filter).listener();
if (listener != null) {
if (t == null) {
listener.onResponse(r, filterInvoker, invocation);
} else {
listener.onError(t, filterInvoker, invocation);
}
}
} else {
filter.onResponse(r, filterInvoker, invocation);
}
}
});
return asyncResult;
}
@Override
public Class<T> getInterface() {
return filterInvoker.getInterface();
}
@Override
public URL getUrl() {
return filterInvoker.getUrl();
}
@Override
public boolean isAvailable() {
return filterInvoker.isAvailable();
}
@Override
public void destroy() {
filterInvoker.destroy();
}
}
private static <T> Invoker<T> buildInvokerChain(final Invoker<T> invoker, String key, String group) {
Invoker<T> last = invoker;
List<Filter> filters = ExtensionLoader.getExtensionLoader(Filter.class).getActivateExtension(invoker.getUrl(), key, group);
if (!filters.isEmpty()) {
for (int i = filters.size() - 1; i >= 0; i--) {
final Filter filter = filters.get(i);
final Invoker<T> next = last;
last = new Invoker<T>() {
@Override
public Class<T> getInterface() {
return invoker.getInterface();
}
@Override
public URL getUrl() {
return invoker.getUrl();
}
@Override
public boolean isAvailable() {
return invoker.isAvailable();
}
// 4、ProtocolFilterWrapper 的 Invoker 中的 invoke 方法
@Override
public Result invoke(Invocation invocation) throws RpcException {
Result asyncResult;
try {
// 按照filter中设置的 order 顺序,order 越小优先级越高,order 默认是 0,顺序调用所有 Filter 的 invoke 方法
asyncResult = filter.invoke(next, invocation);
} catch (Exception e) {
// onError callback
if (filter instanceof ListenableFilter) {
Filter.Listener listener = ((ListenableFilter) filter).listener();
if (listener != null) {
listener.onError(e, invoker, invocation);
}
}
throw e;
}
return asyncResult;
}
@Override
public void destroy() {
invoker.destroy();
}
@Override
public String toString() {
return invoker.toString();
}
};
}
}
return new CallbackRegistrationInvoker<>(last, filters);
}
// 5、ConsumerContextFilter 的 invoke 方法
@Override
public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {
RpcContext.getContext()
.setInvoker(invoker)
.setInvocation(invocation)
.setLocalAddress(NetUtils.getLocalHost(), 0)
.setRemoteAddress(invoker.getUrl().getHost(),
invoker.getUrl().getPort());
if (invocation instanceof RpcInvocation) {
((RpcInvocation) invocation).setInvoker(invoker);
}
try {
RpcContext.removeServerContext();
// 调用 ProtocolFilterWrapper 的 Invoker 的 invoke 方法
return invoker.invoke(invocation);
} finally {
RpcContext.removeContext();
}
}
// 6、FutureFilter 的 invoke 方法
@Override
public Result invoke(final Invoker<?> invoker, final Invocation invocation) throws RpcException {
fireInvokeCallback(invoker, invocation);
// need to configure if there's return value before the invocation in order to help invoker to judge if it's
// necessary to return future.
// 调用 ProtocolFilterWrapper 的 Invoker 的 invoke 方法
return invoker.invoke(invocation);
}
/**
* The invocation interceptor,it will collect the invoke data about this invocation and send it to monitor center
*
* @param invoker service
* @param invocation invocation.
* @return {@link Result} the invoke result
* @throws RpcException
*/
// 7、MonitorFilter 的 invoke 方法
@Override
public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {
if (invoker.getUrl().hasParameter(MONITOR_KEY)) {
invocation.setAttachment(MONITOR_FILTER_START_TIME, String.valueOf(System.currentTimeMillis()));
getConcurrent(invoker, invocation).incrementAndGet(); // count up
}
// 调用 AsyncToSyncInvoker 的 invoke 方法
return invoker.invoke(invocation); // proceed invocation chain
}
// 8、AsyncToSyncInvoker 的 invoke 方法
@Override
public Result invoke(Invocation invocation) throws RpcException {
// 调用 AbstractInvoker 的 invoke 方法
Result asyncResult = invoker.invoke(invocation);
try {
if (InvokeMode.SYNC == ((RpcInvocation) invocation).getInvokeMode()) {
asyncResult.get(Integer.MAX_VALUE, TimeUnit.MILLISECONDS);
}
} catch (InterruptedException e) {
throw new RpcException("Interrupted unexpectedly while waiting for remoting result to return! method: " + invocation.getMethodName() + ", provider: " + getUrl() + ", cause: " + e.getMessage(), e);
} catch (ExecutionException e) {
Throwable t = e.getCause();
if (t instanceof TimeoutException) {
throw new RpcException(RpcException.TIMEOUT_EXCEPTION, "Invoke remote method timeout. method: " + invocation.getMethodName() + ", provider: " + getUrl() + ", cause: " + e.getMessage(), e);
} else if (t instanceof RemotingException) {
throw new RpcException(RpcException.NETWORK_EXCEPTION, "Failed to invoke remote method: " + invocation.getMethodName() + ", provider: " + getUrl() + ", cause: " + e.getMessage(), e);
}
} catch (Throwable e) {
throw new RpcException(e.getMessage(), e);
}
return asyncResult;
}
// 9、调用 AbstractInvoker 的 invoke 方法
@Override
public Result invoke(Invocation inv) throws RpcException {
// if invoker is destroyed due to address refresh from registry, let's allow the current invoke to proceed
if (destroyed.get()) {
// 判断invoker是否被销毁了
logger.warn("Invoker for service " + this + " on consumer " + NetUtils.getLocalHost() + " is destroyed, "
+ ", dubbo version is " + Version.getVersion() + ", this invoker should not be used any longer");
}
RpcInvocation invocation = (RpcInvocation) inv;
// 设置invoker
invocation.setInvoker(this);
if (CollectionUtils.isNotEmptyMap(attachment)) {
// RpcInvocation 中设置 attachment 中的参数
invocation.addAttachmentsIfAbsent(attachment);
}
Map<String, String> contextAttachments = RpcContext.getContext().getAttachments();
if (CollectionUtils.isNotEmptyMap(contextAttachments)) {
/**
* invocation.addAttachmentsIfAbsent(context){@link RpcInvocation#addAttachmentsIfAbsent(Map)}should not be used here,
* because the {@link RpcContext#setAttachment(String, String)} is passed in the Filter when the call is triggered
* by the built-in retry mechanism of the Dubbo. The attachment to update RpcContext will no longer work, which is
* a mistake in most cases (for example, through Filter to RpcContext output traceId and spanId and other information).
*/
// RpcInvocation 中设置 contextAttachments 中的参数
invocation.addAttachments(contextAttachments);
}
// 设置同步、异步有返回值或者异步无返回值类型
invocation.setInvokeMode(RpcUtils.getInvokeMode(url, invocation));
// 如果是异步,RpcInvocation 中设置 id 参数
RpcUtils.attachInvocationIdIfAsync(getUrl(), invocation);
try {
// 调用具体 Invoker 实现,我们使用的 dubbo 协议,故这里调用的是 DubboInvoker 的 doInvoke 方法
return doInvoke(invocation);
} catch (InvocationTargetException e) { // biz exception
Throwable te = e.getTargetException();
if (te == null) {
return AsyncRpcResult.newDefaultAsyncResult(null, e, invocation);
} else {
if (te instanceof RpcException) {
((RpcException) te).setCode(RpcException.BIZ_EXCEPTION);
}
return AsyncRpcResult.newDefaultAsyncResult(null, te, invocation);
}
} catch (RpcException e) {
if (e.isBiz()) {
return AsyncRpcResult.newDefaultAsyncResult(null, e, invocation);
} else {
throw e;
}
} catch (Throwable e) {
return AsyncRpcResult.newDefaultAsyncResult(null, e, invocation);
}
}
最后的实现逻辑在 DubboInvoker 的 doInvoke 方法,代码如下&#x