DUBBO源码学习(四)服务引用的过程

DUBBO源码学习(一)spi机制
DUBBO源码学习(二)注册中心源码解析
DUBBO源码学习(三)v2.7.8-服务的调用过程

本文基于dubbo-v2.7.8版本。

一、服务引用的过程

Dubbo 服务引用的时机是通过 Spring 容器调用 ReferenceBean 的 afterPropertiesSet 方法时引用服务。在引用的过程中,首先Spring 会调用 getObject 方法,并由该方法执行服务引用逻辑。服务的运用有三种,分别是

  1. 引用本地服务(jvm)
  2. 直连远程服务
  3. 通过注册中心调用远程服务

在引用的过程中,dubbo会生成一个invoker,如果是多个注册中心,则是一组invoker,并且会合并多个容错cluster成最终的invoker。最终生成的invoker会通过ProxyFactory 为服务接口生成代理类,并让代理Proxy类去调用 Invoker 逻辑,来避免对业务代码的侵入。

二、源码分析

2.1、ReferenceBean初始化

ReferenceBean实现了 InitializingBean,在Bean的初始化的时候会调用afterPropertiesSet方法:

public class ReferenceBean<T> extends ReferenceConfig<T> implements FactoryBean,
        ApplicationContextAware, InitializingBean, DisposableBean {
       	
    public void afterPropertiesSet() throws Exception {

        // Initializes Dubbo's Config Beans before @Reference bean autowiring
        prepareDubboConfigBeans();

        // 懒加载.
        if (init == null) {
            init = false;
        }

        // eager init if necessary.
        if (shouldInit()) {
            getObject();
        }
    }  
            
    /**
     * 为了保证Initializes dubbo配置在@Reference bean 注入之前
     * beansOfTypeIncludingAncestors方法获取spring容器中第二个入参要求类型的所有bean对象。dubbo就是通过这个方法保证了在调用DubboBootstrap.initialize方法之前,所有的配置对象都已经创建完毕。
     */
    private void prepareDubboConfigBeans() {
        // Refactor 2.7.9
        final boolean includeNonSingletons = true;
        final boolean allowEagerInit = false;
        beansOfTypeIncludingAncestors(applicationContext, ApplicationConfig.class, includeNonSingletons, allowEagerInit);
        beansOfTypeIncludingAncestors(applicationContext, ModuleConfig.class, includeNonSingletons, allowEagerInit);
        beansOfTypeIncludingAncestors(applicationContext, RegistryConfig.class, includeNonSingletons, allowEagerInit);
        beansOfTypeIncludingAncestors(applicationContext, ProtocolConfig.class, includeNonSingletons, allowEagerInit);
        beansOfTypeIncludingAncestors(applicationContext, MonitorConfig.class, includeNonSingletons, allowEagerInit);
        beansOfTypeIncludingAncestors(applicationContext, ProviderConfig.class, includeNonSingletons, allowEagerInit);
        beansOfTypeIncludingAncestors(applicationContext, ConsumerConfig.class, includeNonSingletons, allowEagerInit);
        beansOfTypeIncludingAncestors(applicationContext, ConfigCenterBean.class, includeNonSingletons, allowEagerInit);
        beansOfTypeIncludingAncestors(applicationContext, MetadataReportConfig.class, includeNonSingletons, allowEagerInit);
        beansOfTypeIncludingAncestors(applicationContext, MetricsConfig.class, includeNonSingletons, allowEagerInit);
        beansOfTypeIncludingAncestors(applicationContext, SslConfig.class, includeNonSingletons, allowEagerInit);
    }
            
            
    @Override
    public Object getObject() {
        return get();
    }
        
        
}

2.2、ReferenceConfig#get() 入口

可以看到在初始化的时候,最终会调用到get()方法,此方法是继承自ReferenceConfig的方法:

public class ReferenceConfig<T> extends ReferenceConfigBase<T> {
    
    
    public synchronized T get() {
        if (destroyed) {
            throw new IllegalStateException("The invoker of ReferenceConfig(" + url + ") has already destroyed!");
        }
        //是否有引用
        if (ref == null) {
            // init 方法主要用于处理配置,以及调用 createProxy 生成代理类
            init();
        }
        return ref;
    }
    
}

2.3、ReferenceConfig#init()初始化

public synchronized void init() {
        //只初始化一次
        if (initialized) {
            return;
        }


        if (bootstrap == null) {
            bootstrap = DubboBootstrap.getInstance();
            //获取所有的注册中心
            if (null != this.getRegistries()) {
                bootstrap.registries(this.getRegistries());
            }
            //全局配置初始化
            bootstrap.initialize();
        }

        //校验和更新配置
        checkAndUpdateSubConfigs();

        //本地存根校验
        checkStubAndLocal(interfaceClass);
        //mock校验
        ConfigValidationUtils.checkMock(interfaceClass, this);

        // 添加 side、协议版本信息、时间戳和进程号等信息到 map 中
        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 = methods(interfaceClass);
            //方法处理,无方法则设置*,多方法则通过逗号分割拼接成字符串
            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);
        // 将 ApplicationConfig、ConsumerConfig、ReferenceConfig 等对象的字段信息添加到 map 中
        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";
                // 检测 map 是否包含 methodName.retry
                if (map.containsKey(retryKey)) {
                    String retryValue = map.remove(retryKey);
                    if ("false".equals(retryValue)) {
                        //设置失败重试次数
                        map.put(methodConfig.getName() + ".retries", "0");
                    }
                }
                // 添加 MethodConfig 中的“属性”字段到 attributes
                // 比如 onreturn、onthrow、oninvoke 等
                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);

        //所有参数放入attachment缓存中,到时候会发送到远程端
        serviceMetadata.getAttachments().putAll(map);

        // proxy层创建代理类
        ref = createProxy(map);

        serviceMetadata.setTarget(ref);
        serviceMetadata.addAttribute(PROXY_CLASS_REF, ref);

        // 根据服务名,ReferenceConfig,代理类构建 ConsumerModel
        ConsumerModel consumerModel = repository.lookupReferredService(serviceMetadata.getServiceKey());
        consumerModel.setProxyObject(ref);
        consumerModel.init(attributes);

        initialized = true;

        //校验引用的服务是否可用
        checkInvokerAvailable();

        // 发送服务引用事件
        dispatch(new ReferenceConfigInitializedEvent(this, invoker));
    }
 public void checkAndUpdateSubConfigs() {
        if (StringUtils.isEmpty(interfaceName)) {
            throw new IllegalStateException("<dubbo:reference interface=\"\" /> interface not allow null!");
        }
        //  使用显示配置的module、application 来进行一些全局配置
        completeCompoundConfigs(consumer);
        // 获取消费者的全局配置
        checkDefault();

        // SPI获取ConfigInitializer对应的实现类或者通过url获取configInitializer://配置并执行响应的配置初始化操作
        List<ConfigInitializer> configInitializers = ExtensionLoader.getExtensionLoader(ConfigInitializer.class)
                .getActivateExtension(URL.valueOf("configInitializer://"), (String[]) null);
        configInitializers.forEach(e -> e.initReferConfig(this));

        //将Environment变量注入到当前对象的配置中
        this.refresh();
        if (getGeneric() == null && getConsumer() != null) {
            // 设置 generic
            setGeneric(getConsumer().getGeneric());
        }
        //泛化调用的处理
        if (ProtocolUtils.isGeneric(generic)) {
            interfaceClass = GenericService.class;
        } else {
            try {
                //反射获取调用接口
                interfaceClass = Class.forName(interfaceName, true, Thread.currentThread()
                        .getContextClassLoader());
            } catch (ClassNotFoundException e) {
                throw new IllegalStateException(e.getMessage(), e);
            }
            //解析调用方法
            checkInterfaceAndMethods(interfaceClass, getMethods());
        }

        //舒适化service元数据
        initServiceMetadata(consumer);
        serviceMetadata.setServiceType(getActualInterface());
        // TODO, uncomment this line once service key is unified
        serviceMetadata.setServiceKey(URL.buildKey(interfaceName, group, version));

        //获取服务仓库
        ServiceRepository repository = ApplicationModel.getServiceRepository();
        //获取接口的描述
        ServiceDescriptor serviceDescriptor = repository.registerService(interfaceClass);
        //对应的服务注册消费者
        repository.registerConsumer(
                serviceMetadata.getServiceKey(),
                serviceDescriptor,
                this,
                null,
                serviceMetadata);

        resolveFile();
        ConfigValidationUtils.validateReferenceConfig(this);
        postProcessConfig();
    }

2.4、reference代理proxy类的创建

createProxy首先是根据配置检查是否为本地调用,本地调用是通过 InjvmProtocol 的 refer 方法生成 InjvmInvoker 实例。非本地钓鱼功能需要读取直连配置项,或注册中心 url,并将读取到的 url 存储到 urls 中。然后根据 urls 元素数量进行后续操作。若只有一个url直接通过 Protocol 自适应拓展类构建 Invoker 实例接口。如果是多个注册中心或服务直连 url,此时先根据 url 构建 Invoker。然后再通过 Cluster 合并多个 Invoker,最后调用 ProxyFactory 生成代理类。

 	/**
     * reference代理类的创建
     * @param map
     * @return
     */
    @SuppressWarnings({"unchecked", "rawtypes", "deprecation"})
    private T createProxy(Map<String, String> map) {
        // 本地引用
        if (shouldJvmRefer(map)) {
            // 生成本地引用 URL,协议为 injvm
            URL url = new URL(LOCAL_PROTOCOL, LOCALHOST_VALUE, 0, interfaceClass.getName()).addParameters(map);
            // 调用 refer 方法构建 InjvmInvoker 实例
            invoker = REF_PROTOCOL.refer(interfaceClass, url);
            if (logger.isInfoEnabled()) {
                logger.info("Using injvm service " + interfaceClass.getName());
            }
        // 远程引用
        } else {
            urls.clear();
            // url 不为空,表明用户可能想进行点对点调用
            if (url != null && url.length() > 0) {
                //多个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 = 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())) {
                    //检查配置中心
                    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()));
                            }
                            // 注册中心地址添加 refer 服务消费元数据
                            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
                invoker = REF_PROTOCOL.refer(interfaceClass, urls.get(0));
            } else {
                //多个注册中心需要创建多个invoker
                List<Invoker<?>> invokers = new ArrayList<Invoker<?>>();
                URL registryURL = null;
                for (URL url : urls) {
                    Invoker<?> referInvoker = REF_PROTOCOL.refer(interfaceClass, url);
                    //验证invoker的可用性
                    if (shouldCheck()) {
                        if (referInvoker.isAvailable()) {
                            invokers.add(referInvoker);
                        } else {
                            referInvoker.destroy();
                        }
                    } else {
                        invokers.add(referInvoker);
                    }

                    // 会覆盖前遍历的注册中心,使用最后一条注册中心数据
                    if (UrlUtils.isRegistry(url)) {
                        registryURL = url; // use last registry url
                    }
                }

                if (shouldCheck() && invokers.size() == 0) {
                    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 multi registry cluster"
                            + " use dubbo version " + Version.getVersion());
                }

                if (registryURL != null) {
                    // 默认使用 zone-aware 集群容错策略 来处理多个订阅  zone-aware=org.apache.dubbo.rpc.cluster.support.registry.ZoneAwareCluster
                    //zone-aware的应用在多注册中心的场景。
                    //业务部署假设是双注册中心:
                    //则对应消费端,先在注册中心间选择,再到选定的注册中心选址:
                    String cluster = registryURL.getParameter(CLUSTER_KEY, ZoneAwareCluster.NAME);
                    // 合并invoker ZoneAwareClusterInvoker(StaticDirectory) -> FailoverClusterInvoker(RegistryDirectory, routing happens here) -> Invoker
                    invoker = Cluster.getCluster(cluster, false).join(new StaticDirectory(registryURL, invokers));
                } else {
                    // 直连的处理方式
                    String cluster = CollectionUtils.isNotEmpty(invokers)
                            ?
                            (invokers.get(0).getUrl() != null ? invokers.get(0).getUrl().getParameter(CLUSTER_KEY, ZoneAwareCluster.NAME) :
                                    Cluster.DEFAULT)
                            : Cluster.DEFAULT;
                    //Directory 即服务目录, 服务目录中存储了一些和服务提供者有关的信息,通过服务目录,服务消费者可获取到服务提供者的信息,比如 ip、端口、服务协议等。通过这些信息,服务消费者就可通过 Netty 等客户端进行远程调用。
                    //StaticDirectory 即静态服务目录,顾名思义,它内部存放的 Invoker 是不会变动的。
                    invoker = Cluster.getCluster(cluster).join(new StaticDirectory(invokers));
                }
            }
        }

        if (logger.isInfoEnabled()) {
            logger.info("Refer dubbo service " + interfaceClass.getName() + " from url " + invoker.getUrl());
        }

        //服务元数据保存到本地
        URL consumerURL = new URL(CONSUMER_PROTOCOL, map.remove(REGISTER_IP_KEY), 0, map.get(INTERFACE_KEY), map);
        MetadataUtils.publishServiceDefinition(consumerURL);

        // 通过invoker创建代理(javassist)
        return (T) PROXY_FACTORY.getProxy(invoker, ProtocolUtils.isGeneric(generic));
    }

上述代码涉及到了StaticDirectory。这在dubbo中成为服务目录。服务目录中存储了一些和服务提供者有关的信息,通过服务目录,服务消费者可获取到服务提供者的信息,比如 ip、端口、服务协议等。通过这些信息,服务消费者就可通过 Netty 等客户端进行远程调用。在一个服务集群中,服务提供者数量并不是一成不变的,如果集群中新增了一台机器,相应地在服务目录中就要新增一条服务提供者记录。或者,如果服务提供者的配置修改了,服务目录中的记录也要做相应的更新。
实际上服务目录在获取注册中心的服务配置信息后,会为每条配置信息生成一个 Invoker 对象,并把这个 Invoker 对象存储起来,这个 Invoker 才是服务目录最终持有的对象。
服务目录目前内置的实现有两个,分别为 StaticDirectory 和 RegistryDirectory,它们均是 AbstractDirectory 的子类
StaticDirectory 即静态服务目录,顾名思义,它内部存放的 Invoker 是不会变动的。
RegistryDirectory 是一种动态服务目录,实现了 NotifyListener 接口。当注册中心服务配置发生变化后,RegistryDirectory 可收到与当前服务相关的变化。收到变更通知后,RegistryDirectory 可根据配置变更信息刷新 Invoker 列表。RegistryDirectory 中有几个比较重要的逻辑,第一是 Invoker 的列举逻辑,第二是接收服务配置变更的逻辑,第三是 Invoker 列表的刷新逻辑。接下来按顺序对这三块逻辑进行分析。

下面分析服务引用的过程:
服务引用有两种,一种是本地服务引用,一种是远程服务引用。
本地服务引用的判断:

 protected boolean shouldJvmRefer(Map<String, String> map) {
        URL tmpUrl = new URL("temp", "localhost", 0, map);
        boolean isJvmRefer;
        if (isInjvm() == null) {
            //如果有指定url则不做本地引用
            if (url != null && url.length() > 0) {
                isJvmRefer = false;
            } else {
                // 根据 url 的协议、scope 以及 injvm 等参数检测是否需要本地引用
                // 比如如果用户显式配置了 scope=local,此时 isInjvmRefer 返回 true
                isJvmRefer = InjvmProtocol.getInjvmProtocol().isInjvmRefer(tmpUrl);
            }
        } else {
            isJvmRefer = isInjvm();
        }
        return isJvmRefer;
    }

2.5、refer创建invoker

2.5.1、RegistryProtocol的refer创建invoker

RegistryProtocol#refer主要做了以下操作:
1. 获取注册中心协议类型,并获取注册中心实例。
2. 获取group 配置,根据 group 决定 doRefer 方法的 Cluster 参数。多分组情况下是 MergeableCluster,默认情况下是 FailoverCluster。
3. doRefer 方法创建一个 RegistryDirectory 实例,交由RegistryDirectory 建立路由链路、订阅节点、容错机制的包装,最终获取到服务节点的一个Invoker

    @Override
    @SuppressWarnings("unchecked")
    public <T> Invoker<T> refer(Class<T> type, URL url) throws RpcException {
        //获取注册中心地址
        url = getRegistryUrl(url);
        //注册中心实例
        Registry registry = getRegistry(url);
        if (RegistryService.class.equals(type)) {
            return proxyFactory.getInvoker((T) registry, type, url);
        }

        // 解析url中的参数到map中
        Map<String, String> qs = StringUtils.parseQueryString(url.getParameterAndDecoded(REFER_KEY));
        //group组的解析
        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(Cluster.getCluster(MergeableCluster.NAME), registry, type, url, qs);
            }
        }
        //集群容错
        Cluster cluster = Cluster.getCluster(qs.get(CLUSTER_KEY));
        return doRefer(cluster, registry, type, url, qs);
    }

proxyFactory#getInvoker会调用到JavassistProxyFactory的getInvoker方法:

public class JavassistProxyFactory extends AbstractProxyFactory {
 
     @Override
    public <T> Invoker<T> getInvoker(T proxy, Class<T> type, URL url) {
        // TODO Wrapper cannot handle this scenario correctly: the classname contains '$'
        // 为目标类创建 Wrapper
        final Wrapper wrapper = Wrapper.getWrapper(proxy.getClass().getName().indexOf('$') < 0 ? proxy.getClass() : type);
        // 创建匿名 Invoker 类对象,并实现 doInvoke 方法。
        return new AbstractProxyInvoker<T>(proxy, type, url) {
            @Override
            protected Object doInvoke(T proxy, String methodName,
                                      Class<?>[] parameterTypes,
                                      Object[] arguments) throws Throwable {
                // 调用 Wrapper 的 invokeMethod 方法,invokeMethod 最终会调用目标方法
                return wrapper.invokeMethod(proxy, methodName, parameterTypes, arguments);
            }
        };
    }
}

oRefer 方法创建一个 RegistryDirectory 实例,然后生成服务者消费者链接,并向注册中心进行注册。注册完毕后,紧接着订阅 providers、configurators、routers 等节点下的数据。完成订阅后,RegistryDirectory 会收到这几个节点下的子节点信息。由于一个服务可能部署在多台服务器上,这样就会在 providers 产生多个节点,这个时候就需要 Cluster 将多个服务节点合并为一个,并生成一个 Invoker。

public class RegistryProtocol implements Protocol {	
	protected <T> Invoker<T> doRefer(Cluster cluster, Registry registry, Class<T> type, URL url, Map<String, String> parameters) {
        URL consumerUrl = new URL(CONSUMER_PROTOCOL, parameters.remove(REGISTER_IP_KEY), 0, type.getName(), parameters);
        ClusterInvoker<T> migrationInvoker = getMigrationInvoker(this, cluster, registry, type, url, consumerUrl);
        //invoker的拦截器链
        return interceptInvoker(migrationInvoker, url, consumerUrl);
    }



	protected <T> Invoker<T> interceptInvoker(ClusterInvoker<T> invoker, URL url, URL consumerUrl) {
        //获取所有与注册协议相关的监听器
        List<RegistryProtocolListener> listeners = findRegistryProtocolListeners(url);
        if (CollectionUtils.isEmpty(listeners)) {
            return invoker;
        }

        //监听器与invoker之间的绑定
        for (RegistryProtocolListener listener : listeners) {
            //该方法最终会执行到RegistryProtocol的doCreateInvoker()方法
            listener.onRefer(this, invoker, consumerUrl);
        }
        return invoker;
    }
    
    protected <T> ClusterInvoker<T> doCreateInvoker(DynamicDirectory<T> directory, Cluster cluster, Registry registry, Class<T> type) {
        //目录设置注册中心和协议
        directory.setRegistry(registry);
        directory.setProtocol(protocol);
        // all attributes of REFER_KEY
        Map<String, String> parameters = new HashMap<String, String>(directory.getConsumerUrl().getParameters());
        //  消费者的链接
        URL urlToRegistry = new URL(CONSUMER_PROTOCOL, parameters.remove(REGISTER_IP_KEY), 0, type.getName(), parameters);

        //是否需要注册
        if (directory.isShouldRegister()) {
            directory.setRegisteredConsumerUrl(urlToRegistry);
            //消费者的注册过程,注册到注册中心
            registry.register(directory.getRegisteredConsumerUrl());
        }
        //调用链
        directory.buildRouterChain(urlToRegistry);
        //订阅当前的服务提供者
        directory.subscribe(toSubscribeUrl(urlToRegistry));

        // 一个注册中心可能有多个服务提供者,因此这里需要将多个服务提供者合并为一个
        return (ClusterInvoker<T>) cluster.join(directory);
    }
    
}

2.5.2、DubboProtocol的refer创建invoker

dubbo协议的refer主要使用过AbstractProtocol的refer来进行调用的

public abstract class AbstractProtocol implements Protocol {
    
    public <T> Invoker<T> refer(Class<T> type, URL url) throws RpcException {
        return new AsyncToSyncInvoker<>(protocolBindingRefer(type, url));
    }
}


ExchangeClient#getClients方法用获取了客户端实例,它的底层是NettyClient,Dubbo 会通过 NettyClient 来进行通信:

public class DubboProtocol extends AbstractProtocol {
    
    public <T> Invoker<T> protocolBindingRefer(Class<T> serviceType, URL url) throws RpcException {
        optimizeSerialization(url);

        // 创建dubbo rpc invoker.
        DubboInvoker<T> invoker = new DubboInvoker<T>(serviceType, url, getClients(url), invokers);
        invokers.add(invoker);

        return invoker;
    }
    
     private ExchangeClient[] getClients(URL url) {
        // 获取连接数默认是0 未配置
        int connections = url.getParameter(CONNECTIONS_KEY, 0);
        if (connections == 0) {
            /*
             * The xml configuration should have a higher priority than properties.
             */
            String shareConnectionsStr = url.getParameter(SHARE_CONNECTIONS_KEY, (String) null);
            connections = Integer.parseInt(StringUtils.isBlank(shareConnectionsStr) ? ConfigUtils.getProperty(SHARE_CONNECTIONS_KEY,
                    DEFAULT_SHARE_CONNECTIONS) : shareConnectionsStr);
            // 获取共享客户端
            return getSharedClient(url, connections).toArray(new ExchangeClient[0]);
        } else {
            ExchangeClient[] clients = new ExchangeClient[connections];
            for (int i = 0; i < clients.length; i++) {
                //初始化共享客户端
                clients[i] = initClient(url);
            }
            return clients;
        }

    }
    
     private ExchangeClient initClient(URL url) {

        // 客户端类型,默认netty
        String str = url.getParameter(CLIENT_KEY, url.getParameter(SERVER_KEY, DEFAULT_REMOTING_CLIENT));

        // 添加编解码和心跳包参数到 url 中
        url = url.addParameter(CODEC_KEY, DubboCodec.NAME);
        url = url.addParameterIfAbsent(HEARTBEAT_KEY, String.valueOf(DEFAULT_HEARTBEAT));

        // BIO 是不允许的,因为它有严重的性能问题。
        if (str != null && str.length() > 0 && !ExtensionLoader.getExtensionLoader(Transporter.class).hasExtension(str)) {
            throw new RpcException("Unsupported client type: " + str + "," +
                    " supported client type is " +
                    StringUtils.join(ExtensionLoader.getExtensionLoader(Transporter.class).getSupportedExtensions(), " "));
        }

        ExchangeClient client;
        try {
            // 获取 lazy 配置,并根据配置值决定创建的客户端类型
            if (url.getParameter(LAZY_CONNECT_KEY, false)) {
                // 带懒加载的ExchangeClient 实例
                client = new LazyConnectExchangeClient(url, requestHandler);

            } else {
                // ExchangeClient 实例
                client = Exchangers.connect(url, requestHandler);
            }

        } catch (RemotingException e) {
            throw new RpcException("Fail to create remoting client for service(" + url + "): " + e.getMessage(), e);
        }

        return client;
    }
    
}    

Exchangers#getExchanger 会通过 SPI 加载 HeaderExchangeClient 实例

public class Exchangers {
    public static ExchangeClient connect(URL url, ExchangeHandler handler) throws RemotingException {
        if (url == null) {
            throw new IllegalArgumentException("url == null");
        }
        if (handler == null) {
            throw new IllegalArgumentException("handler == null");
        }
        // 获取 Exchanger 实例,默认为 HeaderExchangeClient
        return getExchanger(url).connect(url, handler);
    }
    
    
    public static Exchanger getExchanger(URL url) {
        String type = url.getParameter(Constants.EXCHANGER_KEY, Constants.DEFAULT_EXCHANGER);
        return getExchanger(type);
    }

    public static Exchanger getExchanger(String type) {
        //spi获取Exchanger的实例
        return ExtensionLoader.getExtensionLoader(Exchanger.class).getExtension(type);
    }
    
}
public class HeaderExchanger implements Exchanger {

    public static final String NAME = "header";

    @Override
    public ExchangeClient connect(URL url, ExchangeHandler handler) throws RemotingException {
        // 这里包含了多个调用,分别如下:
        // 1. 创建 HeaderExchangeHandler 对象
        // 2. 创建 DecodeHandler 对象
        // 3. 通过 Transporters 构建 Client 实例
        // 4. 创建 HeaderExchangeClient 对象
        return new HeaderExchangeClient(Transporters.connect(url, new DecodeHandler(new HeaderExchangeHandler(handler))), true);
    }

    @Override
    public ExchangeServer bind(URL url, ExchangeHandler handler) throws RemotingException {
        // 创建 HeaderExchangeServer 实例,该方法包含了多个逻辑,分别如下:
        //   1. new HeaderExchangeHandler(handler)
        //	 2. new DecodeHandler(new HeaderExchangeHandler(handler))
        //   3. Transporters.bind(url, new DecodeHandler(new HeaderExchangeHandler(handler)))
        return new HeaderExchangeServer(Transporters.bind(url, new DecodeHandler(new HeaderExchangeHandler(handler))));
    }

}

getTransporter 方法返回的是自适应拓展类,该类会在运行时根据客户端类型加载指定的 Transporter 实现类。若用户未配置客户端类型,则默认加载 NettyTransporter,并调用该类的 connect 方法。如下:

public class Transporters {
    public static Client connect(URL url, ChannelHandler... handlers) throws RemotingException {
        if (url == null) {
            throw new IllegalArgumentException("url == null");
        }
        ChannelHandler handler;
        if (handlers == null || handlers.length == 0) {
            handler = new ChannelHandlerAdapter();
        } else if (handlers.length == 1) {
            handler = handlers[0];
        } else {
            // 如果 handler 数量大于1,则创建一个 ChannelHandler 分发器
            handler = new ChannelHandlerDispatcher(handlers);
        }
        // 获取 Transporter 自适应拓展类,并调用 connect 方法生成 Client 实例
        return getTransporter().connect(url, handler);
    }
    
    public static Transporter getTransporter() {
        return ExtensionLoader.getExtensionLoader(Transporter.class).getAdaptiveExtension();
    }
    
}    

最后就是底层的NettyTransporter:

public class NettyTransporter implements Transporter {

    public static final String NAME = "netty3";

    @Override
    public RemotingServer bind(URL url, ChannelHandler handler) throws RemotingException {
        // 创建 NettyServer
        return new NettyServer(url, handler);
    }

    @Override
    public Client connect(URL url, ChannelHandler handler) throws RemotingException {
        // 创建 NettyClient 对象
        return new NettyClient(url, handler);
    }

}

2.6、代理类的创建

上接2.4的代码,Invoker 创建完毕后,需要为服务接口生成代理对象。远程调用是通过代理对象处理的,代理对象生成的入口方法为是ProxyFactory 的 getProxy,默认实现类是JavassistProxyFactory:

public class JavassistProxyFactory extends AbstractProxyFactory {
    
    @Override
    @SuppressWarnings("unchecked")
    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:

public abstract class Proxy {
    
    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
        String key = sb.toString();

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

                // get Class by key.
                Object clazzObj = classCache.get(key);
                if (null == clazzObj || clazzObj instanceof Reference<?>) {
                    Class<?> clazz = null;
                    if (clazzObj instanceof Reference<?>) {
                        clazz = (Class<?>) ((Reference<?>) clazzObj).get();
                    }

                    // 并发控制,保证只有一个线程可以进行后续操作
                    if (null == clazz) {
                        if (value == PENDING_GENERATION_MARKER) {
                            try {
                                cache.wait();
                            } catch (InterruptedException e) {
                            }
                        } else {
                            // 放置标志位到缓存中,并跳出 while 循环进行后续操作
                            cache.put(key, PENDING_GENERATION_MARKER);
                            break;
                        }
                    } else {
                        try {
                            proxy = (Proxy) clazz.newInstance();
                            return proxy;
                        } catch (InstantiationException | IllegalAccessException e) {
                            throw new RuntimeException(e);
                        } finally {
                            if (null == proxy) {
                                cache.remove(key);
                            } else {
                                cache.put(key, new SoftReference<Proxy>(proxy));
                            }
                        }
                    }
                }
            }
            while (true);
        }

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

            Set<String> worked = new HashSet<>();
            List<Method> methods = new ArrayList<>();

            for (int i = 0; i < ics.length; i++) {
                // 检测接口访问级别是否为非public
                if (!Modifier.isPublic(ics[i].getModifiers())) {
                    // 获取接口包名
                    String npkg = ics[i].getPackage().getName();
                    if (pkg == null) {
                        pkg = npkg;
                    } else {
                        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;
                    }

                    worked.add(desc);

                    int ix = methods.size();
                    //返回值类型
                    Class<?> rt = method.getReturnType();
                    //参数类型
                    Class<?>[] pts = method.getParameterTypes();

                    //Object[] args = new Object[N]
                    StringBuilder code = new StringBuilder("Object[] args = new Object[").append(pts.length).append("];");
                    for (int j = 0; j < pts.length; j++) {
                        //args[N] = ($w)$N;
                        code.append(" args[").append(j).append("] = ($w)$").append(j + 1).append(";");
                    }
                    // 生成 InvokerHandler 接口的 invoker 方法调用语句:
                    // Object ret = handler.invoke(this, methods[N], args);
                    code.append(" Object ret = handler.invoke(this, methods[").append(ix).append("], args);");
                    if (!Void.TYPE.equals(rt)) {
                        //非void 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
            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;");

            // 为接口代理类添加带有 InvocationHandler 参数的构造方法,比如:
            // porxy0(java.lang.reflect.InvocationHandler arg0) {
            //     handler=$1;
            // }
            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]));

            // 代理子类名称
            String fcn = Proxy.class.getName() + id;
            ccm = ClassGenerator.newInstance(cl);
            //设置类名
            ccm.setClassName(fcn);
            //默认构造器
            ccm.addDefaultConstructor();
            //父类
            ccm.setSuperClass(Proxy.class);
            // 为 Proxy 的抽象方法 newInstance 生成实现代码,形如:
            // public Object newInstance(java.lang.reflect.InvocationHandler h) {
            //     return new org.apache.dubbo.proxy0($1);
            // }
            ccm.addMethod("public Object newInstance(" + InvocationHandler.class.getName() + " h){ return new " + pcn + "($1); }");
            //生成实现类
            Class<?> pc = ccm.toClass();
            //通过反射创建代理类
            proxy = (Proxy) pc.newInstance();

            synchronized (classCache) {
                classCache.put(key, new SoftReference<Class<?>>(pc));
            }
        } catch (RuntimeException e) {
            throw e;
        } catch (Exception e) {
            throw new RuntimeException(e.getMessage(), e);
        } finally {
            // release ClassGenerator
            if (ccp != null) {
                ccp.release();
            }
            if (ccm != null) {
                ccm.release();
            }
            synchronized (cache) {
                if (proxy == null) {
                    cache.remove(key);
                } else {
                    //缓存代理类 软应用
                    cache.put(key, new SoftReference<>(proxy));
                }
                cache.notifyAll();
            }
        }
        return proxy;
        //ccp 用于为服务接口生成代理类,比如我们有一个 DemoService 接口,这个接口代理类就是由 ccp 生成的。ccm 则是用于为 org.apache.dubbo.common.bytecode.Proxy 抽象类生成子类,主要是实现 Proxy 类的抽象方法。
    }
    
    
}

三、总结:

服务引用的入口在ReferenceBean类下的getObject方法中,通过RegistryProtocol.refer()方法实现数据的拉取、订阅和服务Invoker转换等操作。通过
协议类型会创建对应的注册中心实例,并根据容错策略cluster来合并Invoker。
对于合并的每一个Invoker,会通过监听器去进行具体的实现,如设置基本的服务路由链,进行当前服务的订阅等操作。最终合并到Cluster集群中然后返回。最终返回一个Invoker。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值