dubbo源码系列6-服务调用过程(consumer->provider)

一、前沿

前面分析了 Dubbo SPIprovider服务导出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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值