• dubbo——consumers


    /* org.apache.dubbo.config.bootstrap.DubboBootstrap#start */
        public DubboBootstrap start() {
            if (started.compareAndSet(false, true)) {
                //初始化
                initialize();
                if (logger.isInfoEnabled()) {
                    logger.info(NAME + " is starting...");
                }
                // 暴露dubbo服务(<dubbo:service />注册到注册表)
                exportServices();
    
                // Not only provider register
                if (!isOnlyRegisterProvider() || hasExportedServices()) {
                    // 2. export MetadataService
                    exportMetadataService();
                    //3. Register the local ServiceInstance if required
                    registerServiceInstance();
                }
    
                //引用dubbo服务(<dubbo:reference /> 创建代理)
                referServices();
    
                if (logger.isInfoEnabled()) {
                    logger.info(NAME + " has started.");
                }
            }
            return this;
        }

    DubboBootStrap.referServices():本地创建远程引用代理对象

    /* org.apache.dubbo.config.bootstrap.DubboBootstrap#referServices */
        private void referServices() {
            if (cache == null) {
                cache = ReferenceConfigCache.getCache();
            }
    
            configManager.getReferences().forEach(rc -> {
                // 与alibaba版本的ReferenceConfig兼容,Apache是ReferenceBean类型
                ReferenceConfig referenceConfig = (ReferenceConfig) rc;
                referenceConfig.setBootstrap(this);
    
                //<dubbo:reference init="true"/>立即加载,默认为false
                // 懒加载,延迟到依赖注入时ReferenceBean.getObject()
                if (rc.shouldInit()) {
                    //异步
                    if (referAsync) {
                        CompletableFuture<Object> future = ScheduledCompletableFuture.submit(
                                executorRepository.getServiceExporterExecutor(),
                                () -> cache.get(rc)
                        );
                        asyncReferringFutures.add(future);
                    } else {
                        //同步
                        cache.get(rc);
                    }
                }
            });
        }

    <dubbo:reference init="true" />才会立即加载,默认false,懒加载:需要使用时才会加载,实现方式:

    ReferenceBean是FactoryBean类型,依赖注入时,调用ReferenceBean.getObject()生成一个代理类。

    Reference.getObject():获取Service的引用

    /* org.apache.dubbo.config.spring.ReferenceBean#getObject */
        public Object getObject() {
            return get();
        }
    /* org.apache.dubbo.config.ReferenceConfig#get */
        public synchronized T get() {
            if (destroyed) {
                throw new IllegalStateException("The invoker of ReferenceConfig(" + url + ") has already destroyed!");
            }
            if (ref == null) {
                //初始化
                init();
            }
            return ref;
        }

    init():初始化属性,并且校验,最后根据属性注册到注册表,本地生成接口的代理类

        public synchronized void init() {
            if (initialized) {
                return;
            }
    
            if (bootstrap == null) {
                bootstrap = DubboBootstrap.getInstance();
                bootstrap.init();
            }
            //检查并更新子设置
            checkAndUpdateSubConfigs();
    
            //检查若配置了local或stub,localClass或stubClass必须是interfaceClass的子类
            checkStubAndLocal(interfaceClass);
            //检查熔断接口
            ConfigValidationUtils.checkMock(interfaceClass, this);
    
            // map初始化一些属性,用途:设置到serviceMetadata(元数据)中;生成consumerUrl
            // map.put("init","false")
            // map.put("side","consumer")
            // map.put("application","dubbo-consumer")
            // map.put("register.ip","192.168.56.1")
            // map.put("release","2.7.5")
            // map.put("methods","insertUser,updateUser")
            // map.put("sticky","false")
            // map.put("dubbo","2.0.2")
            // map.put("pid","8748")
            // map.put("interface","org.study.service.UserService")
            // map.put("timestamp","1584282015078")
            Map<String, String> map = new HashMap<String, String>();
            map.put(SIDE_KEY, CONSUMER_SIDE);
    
            ReferenceConfigBase.appendRuntimeParameters(map);
            if (!ProtocolUtils.isGeneric(generic)) {
                String revision = Version.getVersion(interfaceClass, version);
                if (revision != null && revision.length() > 0) {
                    map.put(REVISION_KEY, revision);
                }
    
                String[] methods = Wrapper.getWrapper(interfaceClass).getMethodNames();
                if (methods.length == 0) {
                    logger.warn("No method found in service interface " + interfaceClass.getName());
                    map.put(METHODS_KEY, ANY_VALUE);
                } else {
                    map.put(METHODS_KEY, StringUtils.join(new HashSet<String>(Arrays.asList(methods)), COMMA_SEPARATOR));
                }
            }
            map.put(INTERFACE_KEY, interfaceName);
            AbstractConfig.appendParameters(map, getMetrics());
            AbstractConfig.appendParameters(map, getApplication());
            AbstractConfig.appendParameters(map, getModule());
            // remove 'default.' prefix for configs from ConsumerConfig
            // appendParameters(map, consumer, Constants.DEFAULT_KEY);
            AbstractConfig.appendParameters(map, consumer);
            AbstractConfig.appendParameters(map, this);
            MetadataReportConfig metadataReportConfig = getMetadataReportConfig();
            if (metadataReportConfig != null && metadataReportConfig.isValid()) {
                map.putIfAbsent(METADATA_KEY, REMOTE_METADATA_STORAGE_TYPE);
            }
            Map<String, AsyncMethodInfo> attributes = null;
            if (CollectionUtils.isNotEmpty(getMethods())) {
                attributes = new HashMap<>();
                for (MethodConfig methodConfig : getMethods()) {
                    AbstractConfig.appendParameters(map, methodConfig, methodConfig.getName());
                    String retryKey = methodConfig.getName() + ".retry";
                    if (map.containsKey(retryKey)) {
                        String retryValue = map.remove(retryKey);
                        if ("false".equals(retryValue)) {
                            map.put(methodConfig.getName() + ".retries", "0");
                        }
                    }
                    AsyncMethodInfo asyncMethodInfo = AbstractConfig.convertMethodConfig2AsyncInfo(methodConfig);
                    if (asyncMethodInfo != null) {
    //                    consumerModel.getMethodModel(methodConfig.getName()).addAttribute(ASYNC_KEY, asyncMethodInfo);
                        attributes.put(methodConfig.getName(), asyncMethodInfo);
                    }
                }
            }
    
            String hostToRegistry = ConfigUtils.getSystemProperty(DUBBO_IP_TO_REGISTRY);
            if (StringUtils.isEmpty(hostToRegistry)) {
                hostToRegistry = NetUtils.getLocalHost();
            } else if (isInvalidLocalHost(hostToRegistry)) {
                throw new IllegalArgumentException("Specified invalid registry ip from property:" + DUBBO_IP_TO_REGISTRY + ", value:" + hostToRegistry);
            }
            map.put(REGISTER_IP_KEY, hostToRegistry);
    
            //map数据放入到元数据中
            serviceMetadata.getAttachments().putAll(map);
    
            //创建引用代理,注册到注册表(建立zookeeper的znode)
            ref = createProxy(map);
    
            //设置到元数据中
            serviceMetadata.setTarget(ref);
            serviceMetadata.addAttribute(PROXY_CLASS_REF, ref);
            ConsumerModel consumerModel = repository.lookupReferredService(serviceMetadata.getServiceKey());
            consumerModel.setProxyObject(ref);
            consumerModel.init(attributes);
            //修改哨兵位,已初始化
            initialized = true;
            //后置持利器执行等
            // dispatch a ReferenceConfigInitializedEvent since 2.7.4
            dispatch(new ReferenceConfigInitializedEvent(this, invoker));
        }

    ref = createProxy(map):创建利用注册表,创建本地代理实例

        private T createProxy(Map<String, String> map) {
            if (shouldJvmRefer(map)) {
                //injvm,jvm内的互相调用
                URL url = new URL(LOCAL_PROTOCOL, LOCALHOST_VALUE, 0, interfaceClass.getName()).addParameters(map);
                invoker = REF_PROTOCOL.refer(interfaceClass, url);
                if (logger.isInfoEnabled()) {
                    logger.info("Using injvm service " + interfaceClass.getName());
                }
            } else {
                //jvm外调用
                urls.clear();
                if (url != null && url.length() > 0) { // user specified URL, could be peer-to-peer address, or register center's address.
                    //<dubbo:reference url="*"/>  自定义url
                    String[] us = SEMICOLON_SPLIT_PATTERN.split(url);
                    if (us != null && us.length > 0) {
                        for (String u : us) {
                            URL url = URL.valueOf(u);
                            if (StringUtils.isEmpty(url.getPath())) {
                                url = url.setPath(interfaceName);
                            }
                            if (UrlUtils.isRegistry(url)) {
                                urls.add(url.addParameterAndEncoded(REFER_KEY, StringUtils.toQueryString(map)));
                            } else {
                                urls.add(ClusterUtils.mergeUrl(url, map));
                            }
                        }
                    }
                } else { // assemble URL from register center's configuration
                    // 未自定义url、自动生成url
                    //注册中心地址RegisteyUrl:registry://mcip:2291/org.apache.dubbo.registry.RegistryService?application=dubbo-consumer&backup=mcip:2292,mcip:2293&dubbo=2.0.2&pid=8748&registry=zookeeper&release=2.7.5&timestamp=1584282824127
                    if (!LOCAL_PROTOCOL.equalsIgnoreCase(getProtocol())) {
                        checkRegistry();
                        List<URL> us = ConfigValidationUtils.loadRegistries(this, false);
                        if (CollectionUtils.isNotEmpty(us)) {
                            for (URL u : us) {
                                URL monitorUrl = ConfigValidationUtils.loadMonitor(this, u);
                                if (monitorUrl != null) {
                                    map.put(MONITOR_KEY, URL.encode(monitorUrl.toFullString()));
                                }
                                urls.add(u.addParameterAndEncoded(REFER_KEY, StringUtils.toQueryString(map)));
                            }
                        }
                        if (urls.isEmpty()) {
                            throw new IllegalStateException("No such any registry to reference " + interfaceName + " on the consumer " + NetUtils.getLocalHost() + " use dubbo version " + Version.getVersion() + ", please config <dubbo:registry address="..." /> to your spring config.");
                        }
                    }
                }
    
                if (urls.size() == 1) {
                    //注册中心只有一个时
                    invoker = REF_PROTOCOL.refer(interfaceClass, urls.get(0));
                } else {
                    //注册中心多个时
                    //获取所有的远程服务地址
                    List<Invoker<?>> invokers = new ArrayList<Invoker<?>>();
                    URL registryURL = null;
                    for (URL url : urls) {
                        invokers.add(REF_PROTOCOL.refer(interfaceClass, url));
                        if (UrlUtils.isRegistry(url)) {
                            registryURL = url; // use last registry url
                        }
                    }
                    if (registryURL != null) { // registry url is available
                        // for multi-subscription scenario, use 'zone-aware' policy by default
                        URL u = registryURL.addParameterIfAbsent(CLUSTER_KEY, ZoneAwareCluster.NAME);
                        // The invoker wrap relation would be like: ZoneAwareClusterInvoker(StaticDirectory) -> FailoverClusterInvoker(RegistryDirectory, routing happens here) -> Invoker
                        invoker = CLUSTER.join(new StaticDirectory(u, invokers));
                    } else { // not a registry url, must be direct invoke.
                        invoker = CLUSTER.join(new StaticDirectory(invokers));
                    }
                }
            }
    
            if (shouldCheck() && !invoker.isAvailable()) {
                throw new IllegalStateException("Failed to check the status of the service "
                        + interfaceName
                        + ". No provider available for the service "
                        + (group == null ? "" : group + "/")
                        + interfaceName +
                        (version == null ? "" : ":" + version)
                        + " from the url "
                        + invoker.getUrl()
                        + " to the consumer "
                        + NetUtils.getLocalHost() + " use dubbo version " + Version.getVersion());
            }
            if (logger.isInfoEnabled()) {
                logger.info("Refer dubbo service " + interfaceClass.getName() + " from url " + invoker.getUrl());
            }
            /**
             * @since 2.7.0
             * ServiceData Store
             */
            String metadata = map.get(METADATA_KEY);
            WritableMetadataService metadataService = WritableMetadataService.getExtension(metadata == null ? DEFAULT_METADATA_STORAGE_TYPE : metadata);
            if (metadataService != null) {
                URL consumerURL = new URL(CONSUMER_PROTOCOL, map.remove(REGISTER_IP_KEY), 0, map.get(INTERFACE_KEY), map);
                metadataService.publishServiceDefinition(consumerURL);
            }
            // 创建服务代理,默认javassist方式
            return (T) PROXY_FACTORY.getProxy(invoker, ProtocolUtils.isGeneric(generic));
        }
    invoker = REF_PROTOCOL.refer(interfaceClass, urls.get(0)):生成invoker,实际类型MockClusterInvoker
    /* org.apache.dubbo.registry.integration.RegistryProtocol#refer  */
        public <T> Invoker<T> refer(Class<T> type, URL url) throws RpcException {
            //生成注册中心地址RegistryUrl
            //zookeeper://mcip:2291/org.apache.dubbo.registry.RegistryService?application=dubbo-consumer&backup=mcip:2292,mcip:2293&dubbo=2.0.2&pid=8748&refer=application%3Ddubbo-consumer%26dubbo%3D2.0.2%26init%3Dfalse%26interface%3Dorg.study.service.UserService%26methods%3DgetUserById%2Cupdate%2Cinsert%2CtransactionalTest%2CgetUserByUserId%2Cdelete%26pid%3D8748%26register.ip%3D192.168.56.1%26release%3D2.7.5%26side%3Dconsumer%26sticky%3Dfalse%26timestamp%3D1584282015078&release=2.7.5&timestamp=1584282824127
            url = getRegistryUrl(url);
            Registry registry = registryFactory.getRegistry(url);
            if (RegistryService.class.equals(type)) {
                //RegistryService的底层类,直接创建代理
                return proxyFactory.getInvoker((T) registry, type, url);
            }
    
            // 前面的map,内含11个参数
            Map<String, String> qs = StringUtils.parseQueryString(url.getParameterAndDecoded(REFER_KEY));
            String group = qs.get(GROUP_KEY);
            if (group != null && group.length() > 0) {
                //group不为空
                if ((COMMA_SPLIT_PATTERN.split(group)).length > 1 || "*".equals(group)) {
                    return doRefer(getMergeableCluster(), registry, type, url);
                }
            }
            //创建invoker
            return doRefer(cluster, registry, type, url);
        }
    
        private <T> Invoker<T> doRefer(Cluster cluster, Registry registry, Class<T> type, URL url) {
            RegistryDirectory<T> directory = new RegistryDirectory<T>(type, url);
            directory.setRegistry(registry);
            directory.setProtocol(protocol);
            // 属性map,11个属性
            Map<String, String> parameters = new HashMap<String, String>(directory.getConsumerUrl().getParameters());
            //利用map中属性,生成订阅url,consumerUrl
            //consumer://192.168.56.1/org.study.service.UserService?application=dubbo-consumer&dubbo=2.0.2&init=false&interface=org.study.service.UserService&methods=getUserById,update,insert,transactionalTest,getUserByUserId,delete&pid=8748&release=2.7.5&side=consumer&sticky=false&timestamp=1584282015078
            URL subscribeUrl = new URL(CONSUMER_PROTOCOL, parameters.remove(REGISTER_IP_KEY), 0, type.getName(), parameters);
            if (directory.isShouldRegister()) {
                directory.setRegisteredConsumerUrl(subscribeUrl);
                //注册到zookeeper中心
                //实际创建节点:/dubbo/org.study.service.UserService/consumers/consumer%3A%2F%2F192.168.56.1%2Forg.study.service.UserService%3Fapplication%3Ddubbo-consumer%26category%3Dconsumers%26check%3Dfalse%26dubbo%3D2.0.2%26init%3Dfalse%26interface%3Dorg.study.service.UserService%26methods%3DgetUserById%2Cupdate%2Cinsert%2CtransactionalTest%2CgetUserByUserId%2Cdelete%26pid%3D8748%26release%3D2.7.5%26side%3Dconsumer%26sticky%3Dfalse%26timestamp%3D1584282015078
                registry.register(directory.getRegisteredConsumerUrl());
            }
            directory.buildRouterChain(subscribeUrl);
            //向服务器发送订阅请求
            //创建三个目录节点(已存在不创建)/dubbo/interface/providers、routers、configurators
            //并扫描目录节点下的子节点,找到了providers
            directory.subscribe(toSubscribeUrl(subscribeUrl));
    
            //生成一个url
            //里面包含interface-->registryUrl(zookeeper cluster leader node : zookeeper的集群的主节点)
            //interface-->providerUrl(上面subscribe,扫描providers目录下url时找到的)
            Invoker<T> invoker = cluster.join(directory);
            List<RegistryProtocolListener> listeners = findRegistryProtocolListeners(url);
            if (CollectionUtils.isEmpty(listeners)) {
                return invoker;
            }
    
            RegistryInvokerWrapper<T> registryInvokerWrapper = new RegistryInvokerWrapper<>(directory, cluster, invoker, subscribeUrl);
            for (RegistryProtocolListener listener : listeners) {
                listener.onRefer(this, registryInvokerWrapper);
            }
            return registryInvokerWrapper;
        }
    return (T) PROXY_FACTORY.getProxy(invoker, ProtocolUtils.isGeneric(generic)):创建代理实例
    /* org.apache.dubbo.rpc.proxy.javassist.JavassistProxyFactory#getProxy */
    
        public <T> T getProxy(Invoker<T> invoker, Class<?>[] interfaces) {
            return (T) Proxy.getProxy(interfaces).newInstance(new InvokerInvocationHandler(invoker));
        }

    总结:

    1、与service不同Reference采用延迟加载,使用时才会加载ref引用生成代理类

    2、ReferenceBean实际是一个FactoryBean,接口绑定技术,与mybatis中接口映射器类似。

    3、reference生成代理实例,不仅会扫描注册表对应接口下的providers,还会创建consumers目录,应该是为了监控。

    二、RPC调用

    InvokerInvocationHandler.invoke():代理实例的方法执行

    /* org.apache.dubbo.rpc.proxy.InvokerInvocationHandler#invoke */
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            //Object的方法,直接调用本地
            //其他方法RPC
            if (method.getDeclaringClass() == Object.class) {
                return method.invoke(invoker, args);
            }
            String methodName = method.getName();
            Class<?>[] parameterTypes = method.getParameterTypes();
            if (parameterTypes.length == 0) {
                if ("toString".equals(methodName)) {
                    return invoker.toString();
                } else if ("$destroy".equals(methodName)) {
                    invoker.destroy();
                    return null;
                } else if ("hashCode".equals(methodName)) {
                    return invoker.hashCode();
                }
            } else if (parameterTypes.length == 1 && "equals".equals(methodName)) {
                return invoker.equals(args[0]);
            }
            //封装一个RpcInvocation实例其实就是request
            //RpcInvocation记录RPC调用信息,interface-method(args)
            RpcInvocation rpcInvocation = new RpcInvocation(method, invoker.getInterface().getName(), args);
            //记录serviceKey  group+interface+version
            String serviceKey = invoker.getUrl().getServiceKey();
            rpcInvocation.setTargetServiceUniqueName(serviceKey);
          
            if (consumerModel != null) {
                rpcInvocation.put(Constants.CONSUMER_MODEL, consumerModel);
                rpcInvocation.put(Constants.METHOD_MODEL, consumerModel.getMethodModel(method));
            }
    
            return invoker.invoke(rpcInvocation).recreate();
        }

    AbstractClusterInvoker.invoke()

    /* org.apache.dubbo.rpc.cluster.support.AbstractClusterInvoker#invoke */
        public Result invoke(final Invocation invocation) throws RpcException {
            //检查本地服务是否已销毁
            checkWhetherDestroyed();
    
            // 绑定attachments到invocation中,默认空,跳过
            Map<String, Object> contextAttachments = RpcContext.getContext().getObjectAttachments();
            if (contextAttachments != null && contextAttachments.size() != 0) {
                ((RpcInvocation) invocation).addObjectAttachments(contextAttachments);
            }
            //获取所有的providers
            List<Invoker<T>> invokers = list(invocation);
            //负载均衡策略  默认random
            LoadBalance loadbalance = initLoadBalance(invokers, invocation);
            RpcUtils.attachInvocationIdIfAsync(getUrl(), invocation);
            return doInvoke(invocation, invokers, loadbalance);
        }

    FailoverClusterInvoker.invoke()

    public Result doInvoke(Invocation invocation, final List<Invoker<T>> invokers, LoadBalance loadbalance) throws RpcException {
            List<Invoker<T>> copyInvokers = invokers;
            //检查providers不能为空
            checkInvokers(copyInvokers, invocation);
            //获取调用的方法名
            String methodName = RpcUtils.getMethodName(invocation);
            //调用次数  1+2次重试
            int len = getUrl().getMethodParameter(methodName, RETRIES_KEY, DEFAULT_RETRIES) + 1;
            if (len <= 0) {
                len = 1;
            }
            // 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.
                if (i > 0) {
                    //再次检查invokers.destroyed
                    checkWhetherDestroyed();
                    copyInvokers = list(invocation);
                    // check again
                    checkInvokers(copyInvokers, invocation);
                }
                //负载均衡策略,选取一个invoker
                Invoker<T> invoker = select(loadbalance, invocation, copyInvokers, invoked);
                //标记已经调用过的invoker,重试时,换其他invoker重试
                invoked.add(invoker);
                RpcContext.getContext().setInvokers((List) invoked);
                try {
                    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);
        }

    AsyncToSyncInvoker.invoke()

        public Result invoke(Invocation invocation) throws RpcException {
            Result asyncResult = invoker.invoke(invocation);
    
            try {
                if (InvokeMode.SYNC == ((RpcInvocation) invocation).getInvokeMode()) {
                    /**
                     * NOTICE!
                     * must call {@link java.util.concurrent.CompletableFuture#get(long, TimeUnit)} because
                     * {@link java.util.concurrent.CompletableFuture#get()} was proved to have serious performance drop.
                     */
                    asyncResult.get(Integer.MAX_VALUE, TimeUnit.MILLISECONDS);
                }
            } catch (InterruptedException e) {
                throw new RpcException("Interrupted unexpectedly while waiting for remote 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);
                } else {
                    throw new RpcException(RpcException.UNKNOWN_EXCEPTION, "Fail to invoke remote method: " +
                            invocation.getMethodName() + ", provider: " + getUrl() + ", cause: " + e.getMessage(), e);
                }
            } catch (Throwable e) {
                throw new RpcException(e.getMessage(), e);
            }
            return asyncResult;
        }

    AbstractInvoker.invoke()

        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()) {
                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;
            invocation.setInvoker(this);
            if (CollectionUtils.isNotEmptyMap(attachment)) {
                invocation.addObjectAttachmentsIfAbsent(attachment);
            }
            Map<String, Object> contextAttachments = RpcContext.getContext().getObjectAttachments();
            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).
                 */
                invocation.addObjectAttachments(contextAttachments);
            }
    
            invocation.setInvokeMode(RpcUtils.getInvokeMode(url, invocation));
            RpcUtils.attachInvocationIdIfAsync(getUrl(), invocation);
    
            AsyncRpcResult asyncResult;
            try {
                asyncResult = (AsyncRpcResult) doInvoke(invocation);
            } catch (InvocationTargetException e) { // biz exception
                Throwable te = e.getTargetException();
                if (te == null) {
                    asyncResult = AsyncRpcResult.newDefaultAsyncResult(null, e, invocation);
                } else {
                    if (te instanceof RpcException) {
                        ((RpcException) te).setCode(RpcException.BIZ_EXCEPTION);
                    }
                    asyncResult = AsyncRpcResult.newDefaultAsyncResult(null, te, invocation);
                }
            } catch (RpcException e) {
                if (e.isBiz()) {
                    asyncResult = AsyncRpcResult.newDefaultAsyncResult(null, e, invocation);
                } else {
                    throw e;
                }
            } catch (Throwable e) {
                asyncResult = AsyncRpcResult.newDefaultAsyncResult(null, e, invocation);
            }
            RpcContext.getContext().setFuture(new FutureAdapter(asyncResult.getResponseFuture()));
            return asyncResult;
        }

    DubboInvoker.doInvoke()

        protected Result doInvoke(final Invocation invocation) throws Throwable {
            RpcInvocation inv = (RpcInvocation) invocation;
            final String methodName = RpcUtils.getMethodName(invocation);
            inv.setAttachment(PATH_KEY, getUrl().getPath());
            inv.setAttachment(VERSION_KEY, version);
    
            ExchangeClient currentClient;
            if (clients.length == 1) {
                currentClient = clients[0];
            } else {
                currentClient = clients[index.getAndIncrement() % clients.length];
            }
            try {
                boolean isOneway = RpcUtils.isOneway(getUrl(), invocation);
                int timeout = getUrl().getMethodPositiveParameter(methodName, TIMEOUT_KEY, DEFAULT_TIMEOUT);
                if (isOneway) {
                    boolean isSent = getUrl().getMethodParameter(methodName, Constants.SENT_KEY, false);
                    currentClient.send(inv, isSent);
                    return AsyncRpcResult.newDefaultAsyncResult(invocation);
                } else {
                    ExecutorService executor = getCallbackExecutor(getUrl(), inv);
                   //netty调用发送请求inv = RpcInvocation
                    CompletableFuture<AppResponse> appResponseFuture =
                            currentClient.request(inv, timeout, executor).thenApply(obj -> (AppResponse) obj);
                    // save for 2.6.x compatibility, for example, TraceFilter in Zipkin uses com.alibaba.xxx.FutureAdapter
                    FutureContext.getContext().setCompatibleFuture(appResponseFuture);
                    AsyncRpcResult result = new AsyncRpcResult(appResponseFuture, inv);
                    result.setExecutor(executor);
                    return result;
                }
            } catch (TimeoutException e) {
                throw new RpcException(RpcException.TIMEOUT_EXCEPTION, "Invoke remote method timeout. method: " + invocation.getMethodName() + ", provider: " + getUrl() + ", cause: " + e.getMessage(), e);
            } catch (RemotingException e) {
                throw new RpcException(RpcException.NETWORK_EXCEPTION, "Failed to invoke remote method: " + invocation.getMethodName() + ", provider: " + getUrl() + ", cause: " + e.getMessage(), e);
            }
        }

    由于netty+javassist完全陌生,流程跑了一遍,具体不清晰

  • 相关阅读:
    Redis主从同步分析(转)
    Jedis使用总结【pipeline】【分布式的id生成器】【分布式锁【watch】【multi】】【redis分布式】(转)
    PHP之PDO_MYSQL扩展安装步骤(转)
    MongoDB 那些坑(转)
    CF 222 (DIV 1)
    TC SRM601
    TC SRM600 DIV2
    Github入门教程
    2013长春区域赛总结
    退役了~~~~~~~~~~~~
  • 原文地址:https://www.cnblogs.com/wqff-biubiu/p/12500065.html
Copyright © 2020-2023  润新知