Dubbo服务消费者Consumer调用流程(七)

在上一篇中提到了RegisteryProtocol#doRefer里面的invoker 为 MockClusterInvoker。

我们在ExtensionLoader一节中,漏讲了一个细节,那就是获取自适应扩展类的时候,采用字节码生成技术的时候,生成的$Adaptive类中获取扩展类是通过ExtensionLoader#getExtension来实现的,

里面有个createExtension方法,其中代码段:

//将该instance依次使用包装类包裹
            if (CollectionUtils.isNotEmpty(wrapperClasses)) {
                for (Class<?> wrapperClass : wrapperClasses) {
                    instance = injectExtension((T) wrapperClass.getConstructor(type).newInstance(instance));
                }
            }

这个意思就是说根据SPI文件中定义的包装类,一次包装instance。我们以Cluster举例:

SPI定义:

mock=org.apache.dubbo.rpc.cluster.support.wrapper.MockClusterWrapper
failover=org.apache.dubbo.rpc.cluster.support.FailoverCluster
failfast=org.apache.dubbo.rpc.cluster.support.FailfastCluster
failsafe=org.apache.dubbo.rpc.cluster.support.FailsafeCluster
failback=org.apache.dubbo.rpc.cluster.support.FailbackCluster
forking=org.apache.dubbo.rpc.cluster.support.ForkingCluster
available=org.apache.dubbo.rpc.cluster.support.AvailableCluster
mergeable=org.apache.dubbo.rpc.cluster.support.MergeableCluster
broadcast=org.apache.dubbo.rpc.cluster.support.BroadcastCluster
registryaware=org.apache.dubbo.rpc.cluster.support.RegistryAwareCluster

根据Cluster.class定义

@SPI(FailoverCluster.NAME)
public interface Cluster {

    /**
     * Merge the directory invokers to a virtual invoker.
     *
     * @param <T>
     * @param directory
     * @return cluster invoker
     * @throws RpcException
     */
    @Adaptive
    <T> Invoker<T> join(Directory<T> directory) throws RpcException;

}

实际上是获取到的instance是FailoverCluster,经过Cluster$Adaptive的调用,实际上获取到时MockClusterWrapper包装过的FailoverCluster.同理Protocol也是如此。调用顺序如下:

ProtocolFilterWrapper->ProtocolListenerWrapper->QosProtocolWrapper->RegistryProtocol  接下来讲解如何重refProtocol中获取到MockClusterInvoker

 

在Referenceconfig#createProxy中  invoker = refprotocol.refer(interfaceClass, urls.get(0));会从上面的链中调用最后到RegistryProtocol.refer -> RegistryProtocol.doRefer 直到

Invoker invoker = cluster.join(directory);  这端逻辑就是本文开头所讲的内容。从MockClusterWrapper的join中,我们获取到MockClusterInvoker。

 

调用

从上一节中我们讲到了InvokerInvocationHandler#invoke,那么实际上就是MockClusterInvoker#invoker 

@Override
    public Result invoke(Invocation invocation) throws RpcException {
        Result result = null;

        String value = directory.getUrl().getMethodParameter(invocation.getMethodName(), Constants.MOCK_KEY, Boolean.FALSE.toString()).trim();
        if (value.length() == 0 || value.equalsIgnoreCase("false")) {
            //当没有配置mock,则直接往下调用 服务提供者暴露接口。
            result = this.invoker.invoke(invocation);
        } else if (value.startsWith("force")) {  // 有配置强制mock 的化,那么不进行远端调用,而直接调用本地mock实现
            if (logger.isWarnEnabled()) {
                logger.warn("force-mock: " + invocation.getMethodName() + " force-mock enabled , url : " + directory.getUrl());
            }
            //force:direct mock
            result = doMockInvoke(invocation, null);
        } else {  // 有mock,则当调用服务提供者失败时候,会使用本地mock实现兜底
            //fail-mock
            try {
                result = this.invoker.invoke(invocation);
            } 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;
    }

我们重点看远程服务调用的result = this.invoker.invoke(invocation);那么这个this.invoker是哪个呢? 回到MockClusterWrapper#join,我们直到此时的this.cluster就是failoverCluster,调用其join方法获取到FailoverClusterInvoker

    public <T> Invoker<T> join(Directory<T> directory) throws RpcException {
        return new FailoverClusterInvoker<T>(directory);
    }

接着执行其MockClusterWrapper#invoke方法 -> AbstractClusterInvoker#invoke  ->  FailoverClusterInvoker#doInvoke

    public Result doInvoke(Invocation invocation, final List<Invoker<T>> invokers, LoadBalance loadbalance) throws RpcException {
        List<Invoker<T>> copyInvokers = invokers;
        // 检查invokers,即检查是否有可用的invokers
        checkInvokers(copyInvokers, invocation);
        // 获取方法名
        String methodName = RpcUtils.getMethodName(invocation);
        int len = getUrl().getMethodParameter(methodName, Constants.RETRIES_KEY, Constants.DEFAULT_RETRIES) + 1;
        if (len <= 0) {
            len = 1;
        }
        // le 为记录最后一次错误。
        // retry loop.
        RpcException le = null; // last exception.
        List<Invoker<T>> invoked = new ArrayList<Invoker<T>>(copyInvokers.size()); // invoked invokers.
        Set<String> providers = new HashSet<String>(len);
        for (int i = 0; i < len; i++) {
            //Reselect before retry to avoid a change of candidate `invokers`.
            //NOTE: if `invokers` changed, then `invoked` also lose accuracy.
            // 为了保证准确性,除第一次外,每次循环,都需要重新检查下invokers的活性
            // 一旦某个invoker失活,会被检测到。
            if (i > 0) {
                checkWhetherDestroyed();
                copyInvokers = list(invocation);
                // check again
                checkInvokers(copyInvokers, invocation);
            }
            // 调用负载均衡,选择出某一个invokers
            Invoker<T> invoker = select(loadbalance, invocation, copyInvokers, invoked);
            invoked.add(invoker);
            RpcContext.getContext().setInvokers((List) invoked);
            try {
                // 使用选出的invoker,执行invoke方法。
                Result result = invoker.invoke(invocation);
                if (le != null && logger.isWarnEnabled()) {
                    logger.warn("Although retry the method " + methodName
                            + " in the service " + getInterface().getName()
                            + " was successful by the provider " + invoker.getUrl().getAddress()
                            + ", but there have been failed providers " + providers
                            + " (" + providers.size() + "/" + copyInvokers.size()
                            + ") from the registry " + directory.getUrl().getAddress()
                            + " on the consumer " + NetUtils.getLocalHost()
                            + " using the dubbo version " + Version.getVersion() + ". Last error is: "
                            + le.getMessage(), le);
                }
                return result;
            } catch (RpcException e) {
                if (e.isBiz()) { // biz exception.
                    throw e;
                }
                le = e;
            } catch (Throwable e) {
                le = new RpcException(e.getMessage(), e);
            } finally {
                providers.add(invoker.getUrl().getAddress());
            }
        }
        throw new RpcException(le.getCode(), "Failed to invoke the method "
                + methodName + " in the service " + getInterface().getName()
                + ". Tried " + len + " times of the providers " + providers
                + " (" + providers.size() + "/" + copyInvokers.size()
                + ") from the registry " + directory.getUrl().getAddress()
                + " on the consumer " + NetUtils.getLocalHost() + " using the dubbo version "
                + Version.getVersion() + ". Last error is: "
                + le.getMessage(), le.getCause() != null ? le.getCause() : le);
    }

 

这边的invoker从debug上来看是这样的 先调用了  RegisterDirectory$InvokerDelegate.invoke(InvokerWrapper.invoke)  ->  ListenerInvokerWraper.invoke  -> ProtocolFilterWrapper.invoke  -> DubboInvoke.invoke

 

 

 

 

 

 

 

 


 

posted @ 2022-02-10 10:10  gaojy  阅读(58)  评论(0编辑  收藏  举报