dubbo服務消費過程(一)

如何實現服的消費

  • 生成遠程服務的代理
  • 獲取目標服務的url地址
  • 實現遠程網絡通信
  • 實現負載均衡
  • 實現集羣容錯

在這裏插入圖片描述
Invoker
在這裏插入圖片描述

服務引入

消費端的代碼解析是從下面這段代碼開始的

<dubbo:reference id="xxxService" interface="xxx.xxx.Service"/>

註解的方式的初始化入口是

ReferenceAnnotationBeanPostProcessor
->ReferenceBeanInvocationHandler.init
->ReferenceConfig.get() 獲得一個遠程代理類

ReferenceBean

服務引用的入口方法爲 ReferenceBean 的 getObject 方法,該方法定義在 Spring 的 FactoryBean 接口中

/**
 * ReferenceFactoryBean
 */
public class ReferenceBean<T> extends ReferenceConfig<T> implements FactoryBean,
        ApplicationContextAware, InitializingBean, DisposableBean {
    private static final long serialVersionUID = 213195494150089726L;

    private transient ApplicationContext applicationContext;
    public ReferenceBean() {
        super();
    }
    public ReferenceBean(Reference reference) {
        super(reference);
    }
    @Override
    public void setApplicationContext(ApplicationContext applicationContext) {
        this.applicationContext = applicationContext;
     SpringExtensionFactory.addApplicationContext(applicationContext);
    }
    @Override 
    // 這是入口方法
    public Object getObject() {
        return get();
    }

    @Override
    public Class<?> getObjectType() {
        return getInterfaceClass();
    }
    @Override
    @Parameter(excluded = true)
    public boolean isSingleton() {
        return true;
    }
    /**
     * Initializes there Dubbo's Config Beans before @Reference bean autowiring
     */
    private void prepareDubboConfigBeans() {
        beansOfTypeIncludingAncestors(applicationContext, ApplicationConfig.class);
        beansOfTypeIncludingAncestors(applicationContext, ModuleConfig.class);
        beansOfTypeIncludingAncestors(applicationContext, RegistryConfig.class);
        beansOfTypeIncludingAncestors(applicationContext, ProtocolConfig.class);
        beansOfTypeIncludingAncestors(applicationContext, MonitorConfig.class);
        beansOfTypeIncludingAncestors(applicationContext, ProviderConfig.class);
        beansOfTypeIncludingAncestors(applicationContext, ConsumerConfig.class);
        beansOfTypeIncludingAncestors(applicationContext, ConfigCenterBean.class);
        beansOfTypeIncludingAncestors(applicationContext, MetadataReportConfig.class);
        beansOfTypeIncludingAncestors(applicationContext, MetricsConfig.class);
        beansOfTypeIncludingAncestors(applicationContext, SslConfig.class);
    }

    @Override
    @SuppressWarnings({"unchecked"})
    public void afterPropertiesSet() throws Exception {
        // 加載 dubbo的ConfigBean到ioc容器中
        prepareDubboConfigBeans();

        // 默認懶加載 可以通過@Reference(init = true)
        if (init == null) {
            init = false;
        }

        // eager init if necessary.
        if (shouldInit()) {
            getObject();
        }
    }

    @Override
    public void destroy() {
        // do nothing
    }
}

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;
    }

ReferenceConfig.init

    public synchronized void init() {
    	// 避免重複初始化
        if (initialized) {
            return;
        }
        if (bootstrap == null) {
            bootstrap = DubboBootstrap.getInstance();
            bootstrap.init(); 
        }
		// 檢查和修改配置
        checkAndUpdateSubConfigs();

        //init serivceMetadata 初始化 服務元數據
        serviceMetadata.setVersion(version);
        serviceMetadata.setGroup(group);
        serviceMetadata.setDefaultGroup(group);
        serviceMetadata.setServiceType(getActualInterface());
        serviceMetadata.setServiceInterfaceName(interfaceName);
        // TODO, uncomment this line once service key is unified
        serviceMetadata.setServiceKey(URL.buildKey(interfaceName, group, version));
		// 檢查本地服務
        checkStubAndLocal(interfaceClass);
        ConfigValidationUtils.checkMock(interfaceClass, this);

        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);
        Map<String, Object> 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");
                    }
                }
                ConsumerModel.AsyncMethodInfo asyncMethodInfo = AbstractConfig.convertMethodConfig2AsyncInfo(methodConfig);
                if (asyncMethodInfo != null) {
//                    consumerModel.getMethodModel(methodConfig.getName()).addAttribute(ASYNC_KEY, asyncMethodInfo);
                    attributes.put(methodConfig.getName(), asyncMethodInfo);
                }
            }
        }
 		// 獲取服務消費者 ip 地址
        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);

        serviceMetadata.getAttachments().putAll(map);
        /******************上面都是參數組裝********************/
		// 元數據中心註冊
        ServiceRepository repository = ApplicationModel.getServiceRepository();
        ServiceDescriptor serviceDescriptor = repository.registerService(interfaceClass);
        repository.registerConsumer(
                serviceMetadata.getServiceKey(),
                attributes,
                serviceDescriptor,
                this,
                null,
                serviceMetadata);
		// 創建代理類引用 這個纔是關鍵
        ref = createProxy(map);

        serviceMetadata.setTarget(ref);
        serviceMetadata.addAttribute(PROXY_CLASS_REF, ref);
        repository.lookupReferredService(serviceMetadata.getServiceKey()).setProxyObject(ref);

        initialized = true; // 設置已經初始化

        // dispatch a ReferenceConfigInitializedEvent since 2.7.4
        dispatch(new ReferenceConfigInitializedEvent(this, invoker));
    }

ReferenceConfig.createProxy

  1. 判斷是否爲本地調用,如果是則使用injvm協議進行調用
  2. 判斷是否爲點對點調用,如果是則把url保存到urls集合中,如果url爲1,進入步驟4,如果urls>1,則執行5 3. 如果是配置了註冊中心,遍歷註冊中心,把url添加到urls集合,url爲1,進入步驟4,如果urls>1,則執行5
  3. 直連構建invoker
  4. 構建invokers集合,通過cluster合併多個invoker
  5. 最後調用 ProxyFactory 生成代理類
    private T createProxy(Map<String, String> map) {
    	// 判斷是否是在同一個jvm進程中調用
        if (shouldJvmRefer(map)) {
            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 {
            urls.clear();
            // @Reference(url = "http://xxx") 直連方式
            // url如果不爲空,說明是點對點通信
            if (url != null && url.length() > 0) { // user specified URL, could be peer-to-peer address, or register center's address.
                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);
                        }
                        // 檢測url協議是否爲registry,若是,表明用戶想使用的指定的註冊中心
                        if (UrlUtils.isRegistry(url)) {
                        	// 將map轉換爲查詢字符串,並作爲refer參數的值添加到url中
                            urls.add(url.addParameterAndEncoded(REFER_KEY, StringUtils.toQueryString(map)));
                        } else {
                        	// 合併url,移除服務提供者的一些配置(這些配置來源用戶配置的url屬性)
                        	// 比如線程池相關配置。並保留服務提供者的部分配置,比如版本,group,時間戳等
                        	// 最後合將合併的配置設置url查詢字符串中
                            urls.add(ClusterUtils.mergeUrl(url, map));
                        }
                    }
                }
            } else { // assemble URL from register center's configuration
                // if protocols not injvm checkRegistry
                if (!LOCAL_PROTOCOL.equalsIgnoreCase(getProtocol())) {
                	// 檢驗註冊中心的配置以及是否必要從配置中心組裝url
                    checkRegistry();
                    // 這裏的代碼實現和服務端類似,也是根據註冊中心配置解析等到的url
                    // 這裏的url:registry://192.168.0.4:2181/org.apache.dubbo.registry.RegistryService
                    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.");
                    }
                }
            }
			// 如果配置了一個註冊中心或者一個服務提供者,直接使用refprotocol.refer
            if (urls.size() == 1) {
            	// Protocol$Adaptive --> RegistryProtocol.refer
                invoker = REF_PROTOCOL.refer(interfaceClass, urls.get(0));
            } else { // 配置多個註冊中心
                List<Invoker<?>> invokers = new ArrayList<Invoker<?>>();
                URL registryURL = null;
                for (URL url : urls) { // 遍歷urls生成多個invoker
                    invokers.add(REF_PROTOCOL.refer(interfaceClass, url));
                    if (UrlUtils.isRegistry(url)) {
                        registryURL = url; // use last registry url
                    }
                }
                if (registryURL != null) { // 如果registryURL不爲空,構建靜態directory
                    // 使用ZoneAwareCluster
                    URL u = registryURL.addParameterIfAbsent(CLUSTER_KEY, ZoneAwareCluster.NAME);
                    // 通過Cluster將多個invoker合併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));
                }
            }
        }
		// 檢查invoker的有效性
        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);
        }
        // create service proxy 創建服務代理類
        return (T) PROXY_FACTORY.getProxy(invoker);
    }

protocol.refer

通過指定的協議來調用refer生成一個invoker對象,invoker前面講過,它是一個代理對象。那麼在當前的消費端而言,invoker主要用於執行遠程調用。這個protocol,又是一個自適應擴展點,它得到的是一個Protocol$Adaptive.

private static final Protocol REF_PROTOCOL = ExtensionLoader.getExtensionLoader(Protocol.class).getAdaptiveExtension();

根據當前的協議url,得到一個指定的擴展點,傳遞進來的參數中,協議地址爲registry://,所以,我們可以直接定位到RegistryProtocol.refer代碼
Protocol$Adaptive中的refer方法

  public org.apache.dubbo.rpc.Invoker refer(java.lang.Class arg0, org.apache.dubbo.common.URL arg1) throws org.apache.dubbo.rpc.RpcException {
        if (arg1 == null) throw new IllegalArgumentException("url == null");
        org.apache.dubbo.common.URL url = arg1;
        String extName = (url.getProtocol() == null ? "dubbo" : url.getProtocol());
        if (extName == null)
            throw new IllegalStateException("Failed to get extension (org.apache.dubbo.rpc.Protocol) name from url (" + url.toString() + ") use keys([protocol])");
        org.apache.dubbo.rpc.Protocol extension = (org.apache.dubbo.rpc.Protocol) ExtensionLoader.getExtensionLoader(org.apache.dubbo.rpc.Protocol.class).getExtension(extName);
        return extension.refer(arg0, arg1);
    }

根據當前的協議擴展名registry, 獲得一個被包裝過的RegistryProtocol

RegistryProtocol.refer

  • (1) 組裝註冊中心協議url
  • (2) 判斷是否配置legroup,如果有,則cluster=getMergeableCluster(),構建invoker
  • (3) doRefer構建invoker
   public <T> Invoker<T> refer(Class<T> type, URL url) throws RpcException {
   		// (1) 組裝註冊中心協議rul
   		// url: zookeeper://192.168.0.4:2181/org.apache.dubbo.registry.RegistryService?xxx
        url = getRegistryUrl(url);
        // registryFactory-> RegistryFactory$Aaptive -> zookeeperRegistryFactory.getRegistry
        // registry 最終返回 zookeeperRegistry 使用curator建立到zookeeper的連接 
        Registry registry = registryFactory.getRegistry(url);
        if (RegistryService.class.equals(type)) {
            return proxyFactory.getInvoker((T) registry, type, url);
        }

        // group="a,b" or group="*"
        // 解析group參數,根據group決定cluster的類型
        Map<String, String> qs = StringUtils.parseQueryString(url.getParameterAndDecoded(REFER_KEY));
        String group = qs.get(GROUP_KEY);
        if (group != null && group.length() > 0) {
            if ((COMMA_SPLIT_PATTERN.split(group)).length > 1 || "*".equals(group)) {
            	// 通過SPI加載MergeableCluster實例,並調用doRefer繼續執行
                return doRefer(getMergeableCluster(), registry, type, url);
            }
        }
        // 構建invoker 調用doRefer繼續執行服務引用邏輯
        return doRefer(cluster, registry, type, url);
    }
    // 根據配置的協議組裝url
    protected URL getRegistryUrl(URL url) {
        return URLBuilder.from(url)
                .setProtocol(url.getParameter(REGISTRY_KEY, DEFAULT_REGISTRY))
                .removeParameter(REGISTRY_KEY)
                .build();
    }

RegistryProtocol.doRefer

  • 構建一個RegistryDirectory
  • 構建一個consumer://協議的地址註冊到註冊中心
  • 訂閱zookeeper中節點的變化
  • 調用cluster.join方法
  private <T> Invoker<T> doRefer(Cluster cluster, Registry registry, Class<T> type, URL url) {
  		// RegistryDirectory初始化
        RegistryDirectory<T> directory = new RegistryDirectory<T>(type, url);
        // 設置註冊中心和協議
        directory.setRegistry(registry);
        directory.setProtocol(protocol);
        // all attributes of REFER_KEY
        Map<String, String> parameters = new HashMap<String, String>(directory.getUrl().getParameters());
        // url:consumer://192.168.0.4/com.test.dubbo.DemoService?xxx
        URL subscribeUrl = new URL(CONSUMER_PROTOCOL, parameters.remove(REGISTER_IP_KEY), 0, type.getName(), parameters);
        // 註冊服務消費者,在consumers 目前下新節點
        if (!ANY_VALUE.equals(url.getServiceInterface()) && url.getParameter(REGISTER_KEY, true)) {
            directory.setRegisteredConsumerUrl(getRegisteredConsumerUrl(subscribeUrl, url));
             // 註冊consumer://協議的url
            registry.register(directory.getRegisteredConsumerUrl());
        }
        // 構建routerChain
        directory.buildRouterChain(subscribeUrl);
        // 訂閱 providers,configurators,routers等節點數據
        directory.subscribe(subscribeUrl.addParameter(CATEGORY_KEY,
                PROVIDERS_CATEGORY + "," + CONFIGURATORS_CATEGORY + "," + ROUTERS_CATEGORY));
		// 一個註冊中心可能有多個服務提供者,因此這裏需要將多個服務提供者合併爲一個 後面負責均衡用到
		// 這裏返回的invoker,應該是MockClusterWrapper(FailOverCluster(directory))
        Invoker invoker = cluster.join(directory);
        return invoker;
    }

doRefer 方法創建一個 RegistryDirectory 實例,然後生成服務者消費者鏈接,並向註冊中心進行註冊。註冊完畢後,緊接着訂閱 providers、configurators、routers 等節點下的數據。完成訂閱後,RegistryDirectory 會收到這幾個節點下的子節點信息。由於一個服務可能部署在多臺服務器上,這樣就會在 providers 產生多個節點,這個時候就需要 Cluster 將多個服務節點合併爲一個,並生成一個 Invoker。關於 RegistryDirectory 和 Cluster,這裏不再分析,後面單獨分析。

proxyFactory.getProxy創建代理

ReferenceConfig.createProxy方法中的最後一行,拿到invoker之後,會調用獲得一個動態代理類

 return (T) PROXY_FACTORY.getProxy(invoker);

proxyFactory是一個SPI擴展點 可以直接看StubProxyFactoryWrapper(JavassistProxyFactory)
JavassistProxyFactory中沒有getProxy(xx)一個參數的方法會調用其父類的方法AbstractProxyFactory#getProxy(Invoker<T>)

可以直接從AbstractProxyFactory.getProxy分析

AbstractProxyFactory.getProxy

public abstract class AbstractProxyFactory implements ProxyFactory {
    private static final Class<?>[] INTERNAL_INTERFACES = new Class<?>[]{
            EchoService.class, Destroyable.class
    };

    @Override
    public <T> T getProxy(Invoker<T> invoker) throws RpcException {
    	// 調用重載方法
        return getProxy(invoker, false);
    }

    @Override
    public <T> T getProxy(Invoker<T> invoker, boolean generic) throws RpcException {
        Set<Class<?>> interfaces = new HashSet<>();
		// 獲取接口配置
        String config = invoker.getUrl().getParameter(INTERFACES);
        if (config != null && config.length() > 0) {
        	// 切分接口列表
            String[] types = COMMA_SPLIT_PATTERN.split(config);
            if (types != null && types.length > 0) {
                for (int i = 0; i < types.length; i++) {
                    // TODO can we load successfully for a different classloader?.
                    interfaces.add(ReflectUtils.forName(types[i]));
                }
            }
        }

        if (!GenericService.class.isAssignableFrom(invoker.getInterface()) && generic) {
            interfaces.add(com.alibaba.dubbo.rpc.service.GenericService.class);
        }
		// 添加接口
        interfaces.add(invoker.getInterface());
        // 添加服務類接口 EchoService.class, Destroyable.class
        interfaces.addAll(Arrays.asList(INTERNAL_INTERFACES));
		// 調用模板重載方法 
        return getProxy(invoker, interfaces.toArray(new Class<?>[0]));
    }
	// 模板方法 由子類實現 如:JavassistProxyFactory.getProxy
    public abstract <T> T getProxy(Invoker<T> invoker, Class<?>[] types);

}

JavassistProxyFactory.getProxy

public <T> T getProxy(Invoker<T> invoker, Class<?>[] interfaces) {
   // 生成 Proxy 子類(Proxy 是抽象類)。並調用 Proxy 子類的 newInstance 方法創建 Proxy 實例
    return (T) Proxy.getProxy(interfaces).newInstance(new InvokerInvocationHandler(invoker));
}

通過 Proxy 的 getProxy 方法獲取 Proxy 子類,然後創建 InvokerInvocationHandler 對象,並將該對象傳給 newInstance 生成 Proxy 實例
InvokerInvocationHandler 實現 JDK 的 InvocationHandler 接口,具體的用途是攔截接口類調用

Proxy.getProxy

  public static Proxy getProxy(Class<?>... ics) {
		// 調用重載方法
        return getProxy(ClassUtils.getClassLoader(Proxy.class), ics);
    }
    public static Proxy getProxy(ClassLoader cl, Class<?>... ics) {
        if (ics.length > MAX_PROXY_COUNT) {
            throw new IllegalArgumentException("interface limit exceeded");
        }
        StringBuilder sb = new StringBuilder();
        // 遍歷接口列表
        for (int i = 0; i < ics.length; i++) {
            String itf = ics[i].getName();
            // 檢查類型是否爲接口
            if (!ics[i].isInterface()) {
                throw new RuntimeException(itf + " is not a interface.");
            }
            Class<?> tmp = null;
            try {
            	// 重新加載接口類
                tmp = Class.forName(itf, false, cl);
            } catch (ClassNotFoundException e) {
            }
			// 檢測接口是否相同,這裏tmp有可能爲空
            if (tmp != ics[i]) {
                throw new IllegalArgumentException(ics[i] + " is not visible from class loader");
            }
			// 拼接接口全限定名,分割符爲
            sb.append(itf).append(';');
        }
		// 使用拼接後的接口名作爲key
			//eg: com.alibaba.dubbo.rpc.service.EchoService;com.test.dubbo.DemoService;org.apache.dubbo.rpc.service.Destroyable;
        String key = sb.toString();

        // get cache by class loader.
        final Map<String, Object> cache;
        synchronized (PROXY_CACHE_MAP) {
            cache = PROXY_CACHE_MAP.computeIfAbsent(cl, k -> new HashMap<>());
        }

        Proxy proxy = null;
        synchronized (cache) {
            do {
            	// 從緩存中獲取Reference<Proxy>實例
                Object value = cache.get(key);
                if (value instanceof Reference<?>) {
                    proxy = (Proxy) ((Reference<?>) value).get();
                    if (proxy != null) {
                        return proxy;
                    }
                }
				// 併發控制,保證只有一個線程可以進行後續操作
                if (value == PENDING_GENERATION_MARKER) {
                    try {
                    	// 其他線程在此處進行等待
                        cache.wait();
                    } catch (InterruptedException e) {
                    }
                } else {
                	// 放置標誌爲到緩存,並跳出while循環進行後續操作
                    cache.put(key, PENDING_GENERATION_MARKER);
                    break;
                }
            }
            while (true);
        }

        long id = PROXY_CLASS_COUNTER.getAndIncrement();
        String pkg = null;
        ClassGenerator ccp = null, ccm = null;
        try {
        	// 創建ClassGenerator對象
            ccp = ClassGenerator.newInstance(cl);

            Set<String> worked = new HashSet<>();
            List<Method> methods = new ArrayList<>();
            for (int i = 0; i < ics.length; i++) {
            	// 檢測接口訪問級別是否爲protocted或private
                if (!Modifier.isPublic(ics[i].getModifiers())) {
                	// 獲取接口報名
                    String npkg = ics[i].getPackage().getName();
                    if (pkg == null) {
                        pkg = npkg;
                    } else {
                    	// 非public級別的接口必須在同一個包下,否則拋出異常
                        if (!pkg.equals(npkg)) {
                            throw new IllegalArgumentException("non-public interfaces from different packages");
                        }
                    }
                }
                // 添加接口到ClassGenerator中
                ccp.addInterface(ics[i]);
				// 遍歷接口方法
                for (Method method : ics[i].getMethods()) {
                	// 獲取方法描述,可以理解爲方法簽名
                    String desc = ReflectUtils.getDesc(method);
                    // 如果方法描述字符串已在 worked 中,則忽略。考慮這種情況,
                	// A 接口和 B 接口中包含一個完全相同的方法
                    if (worked.contains(desc) || Modifier.isStatic(method.getModifiers())) {
                        continue;
                    }
                    if (ics[i].isInterface() && Modifier.isStatic(method.getModifiers())) {
                        continue;
                    }
                    worked.add(desc);
                    int ix = methods.size();
                    // 獲取方法返回值類型
                    Class<?> rt = method.getReturnType();
                    Class<?>[] pts = method.getParameterTypes();
					// 生成 Object[] args = new Object[1...N]
                    StringBuilder code = new StringBuilder("Object[] args = new Object[").append(pts.length).append("];");
                    for (int j = 0; j < pts.length; j++) {
                   		// 生成 args[1...N] = ($w)$1...N;
                        code.append(" args[").append(j).append("] = ($w)$").append(j + 1).append(";");
                    }
                    code.append(" Object ret = handler.invoke(this, methods[").append(ix).append("], args);");
                     // 返回值不爲 void
                    if (!Void.TYPE.equals(rt)) {
                    	// 生成返回語句,形如 return (java.lang.String) ret;
                        code.append(" return ").append(asArgument(rt, "ret")).append(";");
                    }
                    methods.add(method);
                    // 添加方法名、訪問控制符、參數列表、方法代碼等信息到 ClassGenerator 中 
                    ccp.addMethod(method.getName(), method.getModifiers(), rt, pts, method.getExceptionTypes(), code.toString());
                }
            }

            if (pkg == null) {
                pkg = PACKAGE_NAME;
            }

            // 構建接口代理類名稱:pkg + ".proxy" + id,比如 org.apache.dubbo.proxy0
            String pcn = pkg + ".proxy" + id;
            ccp.setClassName(pcn);
            ccp.addField("public static java.lang.reflect.Method[] methods;");
             // 生成 private java.lang.reflect.InvocationHandler handler
            ccp.addField("private " + InvocationHandler.class.getName() + " handler;");
            ccp.addConstructor(Modifier.PUBLIC, new Class<?>[]{InvocationHandler.class}, new Class<?>[0], "handler=$1;");
            // 爲接口代理類添加默認構造方法
            ccp.addDefaultConstructor();
            // 生成接口代理類
            Class<?> clazz = ccp.toClass();
            clazz.getField("methods").set(null, methods.toArray(new Method[0]));

            // 構建 Proxy 子類名稱,比如 Proxy1,Proxy2 等
            String fcn = Proxy.class.getName() + id;
            ccm = ClassGenerator.newInstance(cl);
            ccm.setClassName(fcn);
            ccm.addDefaultConstructor();
            ccm.setSuperClass(Proxy.class);
            ccm.addMethod("public Object newInstance(" + InvocationHandler.class.getName() + " h){ return new " + pcn + "($1); }");
            // 生成 Proxy 實現類
            Class<?> pc = ccm.toClass();
            // 通過反射創建 Proxy 實例
            proxy = (Proxy) pc.newInstance();
        } catch (RuntimeException e) {
            throw e;
        } catch (Exception e) {
            throw new RuntimeException(e.getMessage(), e);
        } finally {
            // 釋放資源
            if (ccp != null) {
                ccp.release();
            }
            if (ccm != null) {
                ccm.release();
            }
            synchronized (cache) {
                if (proxy == null) {
                    cache.remove(key);
                } else {
                	// 寫緩存
                    cache.put(key, new WeakReference<Proxy>(proxy));
                }
                // 喚醒其他等待線程
                cache.notifyAll();
            }
        }
        return proxy;
    }

在這裏插入圖片描述
最終會生成如proxy0類

package org.apache.dubbo.common.bytecode;

public class proxy0 implements com.test.dubbo.DemoService, EchoService, DemoService {

    public static java.lang.reflect.Method[] methods;

    private java.lang.reflect.InvocationHandler handler;

    public proxy0() {
    }
    public proxy0(java.lang.reflect.InvocationHandler arg0) {
        handler = $1;
    }

    public java.lang.String sayHello(java.lang.String arg0) {
    	// 將參數存儲到 Object 數組中
        Object[] args = new Object[1];
        args[0] = ($w) $1;
        // 調用 InvocationHandler 實現類的 invoke 方法得到調用結果
        Object ret = handler.invoke(this, methods[0], args);
        // 返回調用結果
        return (java.lang.String) ret;
    }
    /** 回聲測試方法 */
    public Object $echo(Object object) {
        Object[] arrobject = new Object[]{object};
        Object object2 = this.handler.invoke(this, methods[1], arrobject);
        return object2;
   }
}

從這個sayHello方法可以看出,我們通過@Reference注入的一個對象實例本質上就是一個動態代理類,通過調用這個類中的方法,會觸發
handler.invoke(), 而這個handler就是InvokerInvocationHandler

服務調用

proxy0#sayHello(String)> InvokerInvocationHandler#invoke(Object, Method, Object[])> MockClusterInvoker#invoke(Invocation)> AbstractClusterInvoker#invoke(Invocation)> FailoverClusterInvoker#doInvoke(Invocation, List<Invoker<T>>, LoadBalance)> Filter#invoke(Invoker, Invocation)  // 包含多個 Filter 調用> ListenerInvokerWrapper#invoke(Invocation)> AbstractInvoker#invoke(Invocation)> DubboInvoker#doInvoke(Invocation)> ReferenceCountExchangeClient#request(Object, int)> HeaderExchangeClient#request(Object, int)> HeaderExchangeChannel#request(Object, int)> AbstractPeer#send(Object)> AbstractClient#send(Object, boolean)> NettyChannel#send(Object, boolean)> NioClientSocketChannel#write(Object)

消費者服務調用 invoker的鏈條調用 回顧上面的Proxy0$sayHello()調用 handler.invoke

 public java.lang.String sayHello(java.lang.String arg0) {
    	// 將參數存儲到 Object 數組中
        Object[] args = new Object[1];
        args[0] = ($w) $1;
        // 調用 InvocationHandler 實現類的 invoke 方法得到調用結果
        Object ret = handler.invoke(this, methods[0], args);
        // 返回調用結果
        return (java.lang.String) ret;
    }

proxy0.handler是在JavassistProxyFactory.getProxy獲取代理類時構造的,入口InvokerInvocationHandler

 return (T) Proxy.getProxy(interfaces).newInstance(new InvokerInvocationHandler(invoker));

InvokerInvocationHandler

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 {
        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]);
        }
        // 將method和args封裝到RpcInvocation中,傳輸對象,並執行後續的調用
        RpcInvocation rpcInvocation = new RpcInvocation(method, invoker.getInterface().getName(), args);
        rpcInvocation.setTargetServiceUniqueName(invoker.getUrl().getServiceKey());
		// 這個invoker是MockClusterInvoker 是通過Cluster的擴展點的包裝類MockClusterWrapper構建的
        return invoker.invoke(rpcInvocation).recreate();
    }
}

MockClusterInvoker.invoke

Mock,在這裏面有兩個邏輯

  1. 是否客戶端強制配置了mock調用,那麼在這種場景中主要可以用來解決服務端還沒開發好的時候
    直接使用本地數據進行測試
  2. 是否出現了異常,如果出現異常則使用配置好的Mock類來實現服務的降級
public class MockClusterInvoker<T> implements Invoker<T> {
    private static final Logger logger = LoggerFactory.getLogger(MockClusterInvoker.class);
    private final Directory<T> directory;
    private final Invoker<T> invoker;
    public MockClusterInvoker(Directory<T> directory, Invoker<T> invoker) {
        this.directory = directory;
        this.invoker = invoker;
    }
    @Override
    public URL getUrl() {
        return directory.getUrl();
    }
    @Override
    public boolean isAvailable() {
        return directory.isAvailable();
    }
    @Override
    public void destroy() {
        this.invoker.destroy();
    }
    @Override
    public Class<T> getInterface() {
        return directory.getInterface();
    }

    @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邏輯,直接調用其他Invoker對象的inoker方法
            // 比如: FailOverCluster 可以通過:@Reference(cluster="failover")配置
            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:xx 直接執行mock邏輯,不乏其遠程調用
            result = doMockInvoke(invocation, null);
        } else {
            //fail-mock
            // fail:xxx 表示消費方調用服務失敗後,再執行mock邏輯,不拋出異常
            try {
            	// 調用其他的Invoker對象的invoke方法
                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);
                }
                // 非業務異常 調用降級mock邏輯
                result = doMockInvoke(invocation, e);
            }
        }
        return result;
    }
    // 省略其他方法 
}    

AbstractClusterInvoker.invoke

下一個invoke,應該是FailoverClusterInvoker,它本身沒有invoke方法,直接進入其父類AbstractClusterInvoker的invoker方法,有回調它的模板方法doInvoke

public abstract class AbstractClusterInvoker<T> implements Invoker<T> {
	// 保存從註冊中心的拉取的所有invoker 目錄  
    protected Directory<T> directory;
    protected boolean availablecheck; // 可用性檢查
    private AtomicBoolean destroyed = new AtomicBoolean(false);
    // 粘性invoker 是否支持粘性調用
    private volatile Invoker<T> stickyInvoker = null;
 	@Override
    public Result invoke(final Invocation invocation) throws RpcException {
        checkWhetherDestroyed();
        // binding attachments into invocation.
        //  隱式參數
        // 綁定attachments,Dubbo中,可以通過 RpcContext 上的 setAttachment 和 getAttachment 
        // 在服務消費方和提供方之間進行參數的隱式傳遞,所以這段代碼中會去綁定attachments
        Map<String, String> contextAttachments = RpcContext.getContext().getAttachments();
        if (contextAttachments != null && contextAttachments.size() != 0) {
            ((RpcInvocation) invocation).addAttachments(contextAttachments);
        }
        // 通過list獲取invoker列表,這個列表是從directory裏面獲得的
        List<Invoker<T>> invokers = list(invocation);
        // 加載loadBalance
        LoadBalance loadbalance = initLoadBalance(invokers, invocation);
        RpcUtils.attachInvocationIdIfAsync(getUrl(), invocation);
        return doInvoke(invocation, invokers, loadbalance);
    }
    protected List<Invoker<T>> list(Invocation invocation) throws RpcException {
    	// 調用Directory的list方法列舉Invoker
        return directory.list(invocation);
    }
	// 初始化負載均衡策略
  	protected LoadBalance initLoadBalance(List<Invoker<T>> invokers, Invocation invocation) {
  	// 通過SPI獲取LoadBalance  默認 random 
        if (CollectionUtils.isNotEmpty(invokers)) {
            return ExtensionLoader.getExtensionLoader(LoadBalance.class).getExtension(invokers.get(0).getUrl()
                    .getMethodParameter(RpcUtils.getMethodName(invocation), LOADBALANCE_KEY, DEFAULT_LOADBALANCE));
        } else {
            return ExtensionLoader.getExtensionLoader(LoadBalance.class).getExtension(DEFAULT_LOADBALANCE);
        }
    }
}

FailoverClusterInvoker.doInvoke

容錯機制
容錯的邏輯:failover失敗重試

  • 獲得重試的次數,並且進行循環
  • 獲得目標服務,並且記錄當前已經調用過的目標服務防止下次繼續將請求發送過去
  • 如果執行成功,則返回結果
  • 如果出現異常,判斷是否爲業務異常,如果是則拋出,否則,進行下一次重試
  public Result doInvoke(Invocation invocation, final List<Invoker<T>> invokers, LoadBalance loadbalance) throws RpcException {
        List<Invoker<T>> copyInvokers = invokers;
        checkInvokers(copyInvokers, invocation);
        String methodName = RpcUtils.getMethodName(invocation);
        // 獲取重試次數 默認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++) {
            if (i > 0) {
                checkWhetherDestroyed();
                // 在進行重試前重新列舉 Invoker,這樣做的好處是,如果某個服務掛了,
                // 通過調用 list 可得到最新可用的 Invoker 列表
                copyInvokers = list(invocation);
                // 對 copyinvokers 進行判空檢查
                checkInvokers(copyInvokers, invocation);
            }
            // 通過負載均衡選擇invoker
            Invoker<T> invoker = select(loadbalance, invocation, copyInvokers, invoked);
            // 記錄已經調用過的服務,下次調用會進行過濾
            invoked.add(invoker);
            // 設置 invoked 到 RPC 上下文中
            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()) { // 如果是業務異常,直接拋出不進行重試
                    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);
    }

toInvokers

RegistryDirectory
在RegistryDirectory中有一個成員屬性,保存了服務地方地址對應的invoke信息

private volatile Map<String, Invoker<T>> urlInvokerMap;

toInvokers
這個invoker是動態的,基於註冊中心的變化而變化的。它的初始化過程的鏈路是
RegistryDirectory.notify->refreshInvoker->toInvokers

 if (enabled) {
    invoker = new InvokerDelegate<>(protocol.refer(serviceType, url), url, providerUrl);
 }

基於protocol.refer來構建的invoker,並且使用InvokerDelegate進行了委託,在DubboProtocol中,
是這樣構建invoker的。返回的是一個DubboInvoker對象

	// AbstractProtocol#refer
   @Override
   public <T> Invoker<T> refer(Class<T> type, URL url) throws RpcException {
       return new AsyncToSyncInvoker<>(protocolBindingRefer(type, url));
   }
   // DubboProtocol#protocolBindingRefer
    public <T> Invoker<T> protocolBindingRefer(Class<T> serviceType, URL url) throws RpcException {
        optimizeSerialization(url);
        // create rpc invoker.
        DubboInvoker<T> invoker = new DubboInvoker<T>(serviceType, url, getClients(url), invokers);
        invokers.add(invoker);
        return invoker;
    }

綜合上述通過url轉成的invoker是
InvokerDelegate
->QosProtocolWrapper->ProtocolListenerWrapper->ProtocolFilterWrapper
->AbstractProtocol->DubboProtocol
->AsyncToSyncInvoker // 異步到同步invoke
->DubboInvoker

DubboInvoker

AbstractInvoker#invoke

// 對Invocation的attachments進行處理,把attachment加入到Invocation中
 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;
        // 設置invoker
        invocation.setInvoker(this);
        if (CollectionUtils.isNotEmptyMap(attachment)) {
        	// 設置attachment
            invocation.addAttachmentsIfAbsent(attachment);
        }
        Map<String, String> contextAttachments = RpcContext.getContext().getAttachments();
        if (CollectionUtils.isNotEmptyMap(contextAttachments)) {
  			// 添加 contextAttachments 到 RpcInvocation#attachment 變量中
            invocation.addAttachments(contextAttachments);
        }
		// 設置調用模式 同步/異步調用
        invocation.setInvokeMode(RpcUtils.getInvokeMode(url, invocation));
        // 設置異步調用Id
        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);
        }
        // 封裝CompletableFuture 異步調用返回
        RpcContext.getContext().setFuture(new FutureAdapter(asyncResult.getResponseFuture()));
        return asyncResult;
}
protected abstract Result doInvoke(Invocation invocation) throws Throwable;

DubboInvoker.doInvoke

  @Override
    protected Result doInvoke(final Invocation invocation) throws Throwable {
        RpcInvocation inv = (RpcInvocation) invocation;
      	// 獲取調用方法名
        final String methodName = RpcUtils.getMethodName(invocation);
        // 設置path和version到attachment中
        inv.setAttachment(PATH_KEY, getUrl().getPath());
        inv.setAttachment(VERSION_KEY, version);
        ExchangeClient currentClient;
        // 從clients數組中獲取ExchangeClient
        if (clients.length == 1) {
            currentClient = clients[0];
        } else {
            currentClient = clients[index.getAndIncrement() % clients.length];
        }
        try {
        	// 獲取異步配置 
            boolean isOneway = RpcUtils.isOneway(getUrl(), invocation);
           	// 獲取超時數據 默認是 1s
            int timeout = getUrl().getMethodPositiveParameter(methodName, TIMEOUT_KEY, DEFAULT_TIMEOUT);
            // oneWay 爲true 表示“單向"通信 沒有返回值  kafka的消費發送方式  也有 oneWay
            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);
                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);
        }
    }
	protected ExecutorService getCallbackExecutor(URL url, Invocation inv) {
        ExecutorService sharedExecutor = ExtensionLoader.getExtensionLoader(ExecutorRepository.class).getDefaultExtension().getExecutor(url);
        if (InvokeMode.SYNC == RpcUtils.getInvokeMode(getUrl(), inv)) {
            return new ThreadlessExecutor(sharedExecutor);
        } else {
            return sharedExecutor;
        }
    }

ExchangeClient

ReferenceCountExchangeClient(HeaderExchangeClient())
調用鏈路
ReferenceCountExchangeClient->HeaderExchangeClient->HeaderExchangeChannel->(request())
把構建好的RpcInvocation,組裝到一個Request對象中進行傳遞

HeaderExchangeChannel#request()

 public CompletableFuture<Object> request(Object request, int timeout, ExecutorService executor) throws RemotingException {
        if (closed) {
            throw new RemotingException(this.getLocalAddress(), null, "Failed to send request " + request + ", cause: The channel " + this + " is closed!");
        }
        // 創建請求對象
        Request req = new Request();
        req.setVersion(Version.getProtocolVersion());
        req.setTwoWay(true);
        req.setData(request);
        DefaultFuture future = DefaultFuture.newFuture(channel, req, timeout, executor);
        try { 
            channel.send(req); // NettyClient
        } catch (RemotingException e) {
            future.cancel();
            throw e;
        }
        return future;
    }

channel.send(req)調用鏈路
AbstractPeer.send ->AbstractClient.send->NettyChannel.send
最終 通過NioSocketChannel把消息發送出去

 ChannelFuture future = channel.writeAndFlush(msg);
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章