dubbo消费者原理

171 阅读7分钟

引言

在调用远程服务时就像调用本地方法一样,其内部究竟是如何实现的呢???

如:在项目xml中定义

<dubbo :reference interface ="com.fei.sys.ICarProvider" id ="carProvider" init ="false" />

然后引用

@Resource
private ICarProvider carProvider;

再调用

carProvider.sayHello();
那么我们就来看看消费者是如何进行服务调用的

创建代理类

Dubbo加载referenceBean的流程 1、解析在DubboNamespaceHandler把配置解析成为BeanDefine对象 2、走spring对象初始化、实例化

ReferenceBean 类的内容非常丰富,逻辑也比较复杂,但是归根结底主要有三个功能,分别是配置初始化、服务订阅和创建代理对象。

下图是ReferenceBean类的继承结构。

从图中看到 ReferenceBean 继承了ReferenceConfig类,实现了FactoryBean, ApplicationContextAware, InitializingBean, DisposableBean这些接口。

FactoryBean:简单工厂一般用在初始化比较复杂的对象,此处主要在返回对远程服务调用的代理类的实现

ApplicationContextAware:实现此接口可以得到ApplicationContext中的所有Bean

InitializingBean:为Bean提供初始化方式,afterPropertiesSet在初始化时都会执行

DisposableBean:提供销毁的方法,在Bean销毁时能够回调执行

dubbo核心类ReferenceConfig继承了AbstractReferenceConfig、AbstractInterfaceConfig、AbstractMethodConfig、AbstractConfig

AbstractConfig:配置解析的工具方法和公用方法

AbstractMethodConfig:封装了配置文件标签中方法级别的相关属性

AbstractInterfaceConfig:封装了配置文件标签中接口级别的相关属性

AbstractReferenceConfig:封装了引用实例的默认配置,比如检查服务实例是否存在,是否使用泛化接口

ReferenceConfig:封装了全局配置,包括接口名、方法配置、默认配置

配置初始化

在ReferenceBean的afterPropertiesSet方法中

public void afterPropertiesSet() throws Exception {
        if (this.applicationContext != null) {
            BeanFactoryUtils.beansOfTypeIncludingAncestors(this.applicationContext, ConfigCenterBean.class, false, false);
        }
        Map monitorConfigMap;
        Iterator var3;
        //如果consumer未注册,则执行
        if (this.getConsumer() == null) {
            monitorConfigMap = this.applicationContext == null ? null : BeanFactoryUtils.beansOfTypeIncludingAncestors(this.applicationContext, ConsumerConfig.class, false, false);
            if (monitorConfigMap != null && monitorConfigMap.size() > 0) {
                ConsumerConfig consumerConfig = null;
                var3 = monitorConfigMap.values().iterator();
                label267:
                while(true) {
                    ConsumerConfig config;
                    do {
                        if (!var3.hasNext()) {
                            if (consumerConfig != null) {
                                this.setConsumer(consumerConfig);
                            }
                            break label267;
                        }
                        config = (ConsumerConfig)var3.next();
                    } while(config.isDefault() != null && !config.isDefault().booleanValue());

                    if (consumerConfig != null) {
                        throw new IllegalStateException("Duplicate consumer configs: " + consumerConfig + " and " + config);
                    }
                    consumerConfig = config;
                }
            }
        }

        if (this.getApplication() == null && (this.getConsumer() == null || this.getConsumer().getApplication() == null)) {
            monitorConfigMap = this.applicationContext == null ? null : BeanFactoryUtils.beansOfTypeIncludingAncestors(this.applicationContext, ApplicationConfig.class, false, false);
            if (monitorConfigMap != null && monitorConfigMap.size() > 0) {
                ApplicationConfig applicationConfig = null;
                ApplicationConfig config;
                for(var3 = monitorConfigMap.values().iterator(); var3.hasNext(); applicationConfig = config) {
                    config = (ApplicationConfig)var3.next();
                    if (applicationConfig != null) {
                        throw new IllegalStateException("Duplicate application configs: " + applicationConfig + " and " + config);
                    }
                }
                if (applicationConfig != null) {
                    this.setApplication(applicationConfig);
                }
            }
        }

        if (this.getModule() == null && (this.getConsumer() == null || this.getConsumer().getModule() == null)) {
            monitorConfigMap = this.applicationContext == null ? null : BeanFactoryUtils.beansOfTypeIncludingAncestors(this.applicationContext, ModuleConfig.class, false, false);
            if (monitorConfigMap != null && monitorConfigMap.size() > 0) {
                ModuleConfig moduleConfig = null;
                var3 = monitorConfigMap.values().iterator();

                label231:
                while(true) {
                    ModuleConfig config;
                    do {
                        if (!var3.hasNext()) {
                            if (moduleConfig != null) {
                                this.setModule(moduleConfig);
                            }
                            break label231;
                        }
                        config = (ModuleConfig)var3.next();
                    } while(config.isDefault() != null && !config.isDefault().booleanValue());

                    if (moduleConfig != null) {
                        throw new IllegalStateException("Duplicate module configs: " + moduleConfig + " and " + config);
                    }
                    moduleConfig = config;
                }
            }
        }

        if (StringUtils.isEmpty(this.getRegistryIds())) {
            if (this.getApplication() != null && StringUtils.isNotEmpty(this.getApplication().getRegistryIds())) {
                this.setRegistryIds(this.getApplication().getRegistryIds());
            }

            if (this.getConsumer() != null && StringUtils.isNotEmpty(this.getConsumer().getRegistryIds())) {
                this.setRegistryIds(this.getConsumer().getRegistryIds());
            }
        }

        if (CollectionUtils.isEmpty(this.getRegistries()) && (this.getConsumer() == null || CollectionUtils.isEmpty(this.getConsumer().getRegistries())) && (this.getApplication() == null || CollectionUtils.isEmpty(this.getApplication().getRegistries()))) {
            monitorConfigMap = this.applicationContext == null ? null : BeanFactoryUtils.beansOfTypeIncludingAncestors(this.applicationContext, RegistryConfig.class, false, false);
            if (monitorConfigMap != null && monitorConfigMap.size() > 0) {
                List<RegistryConfig> registryConfigs = new ArrayList();
                if (StringUtils.isNotEmpty(this.registryIds)) {
                    Arrays.stream(Constants.COMMA_SPLIT_PATTERN.split(this.registryIds)).forEach((id) -> {
                        if (monitorConfigMap.containsKey(id)) {
                            registryConfigs.add(monitorConfigMap.get(id));
                        }

                    });
                }

                if (registryConfigs.isEmpty()) {
                    var3 = monitorConfigMap.values().iterator();

                    while(var3.hasNext()) {
                        RegistryConfig config = (RegistryConfig)var3.next();
                        if (StringUtils.isEmpty(this.registryIds)) {
                            registryConfigs.add(config);
                        }
                    }
                }

                if (!registryConfigs.isEmpty()) {
                    super.setRegistries(registryConfigs);
                }
            }
        }

        if (this.getMetadataReportConfig() == null) {
            monitorConfigMap = this.applicationContext == null ? null : BeanFactoryUtils.beansOfTypeIncludingAncestors(this.applicationContext, MetadataReportConfig.class, false, false);
            if (monitorConfigMap != null && monitorConfigMap.size() == 1) {
                super.setMetadataReportConfig((MetadataReportConfig)monitorConfigMap.values().iterator().next());
            } else if (monitorConfigMap != null && monitorConfigMap.size() > 1) {
                throw new IllegalStateException("Multiple MetadataReport configs: " + monitorConfigMap);
            }
        }

        if (this.getConfigCenter() == null) {
            monitorConfigMap = this.applicationContext == null ? null : BeanFactoryUtils.beansOfTypeIncludingAncestors(this.applicationContext, ConfigCenterConfig.class, false, false);
            if (monitorConfigMap != null && monitorConfigMap.size() == 1) {
                super.setConfigCenter((ConfigCenterConfig)monitorConfigMap.values().iterator().next());
            } else if (monitorConfigMap != null && monitorConfigMap.size() > 1) {
                throw new IllegalStateException("Multiple ConfigCenter found:" + monitorConfigMap);
            }
        }

        if (this.getMonitor() == null && (this.getConsumer() == null || this.getConsumer().getMonitor() == null) && (this.getApplication() == null || this.getApplication().getMonitor() == null)) {
            monitorConfigMap = this.applicationContext == null ? null : BeanFactoryUtils.beansOfTypeIncludingAncestors(this.applicationContext, MonitorConfig.class, false, false);
            if (monitorConfigMap != null && monitorConfigMap.size() > 0) {
                MonitorConfig monitorConfig = null;
                var3 = monitorConfigMap.values().iterator();

                label169:
                while(true) {
                    MonitorConfig config;
                    do {
                        if (!var3.hasNext()) {
                            if (monitorConfig != null) {
                                this.setMonitor(monitorConfig);
                            }
                            break label169;
                        }
                        config = (MonitorConfig)var3.next();
                    } while(config.isDefault() != null && !config.isDefault().booleanValue());

                    if (monitorConfig != null) {
                        throw new IllegalStateException("Duplicate monitor configs: " + monitorConfig + " and " + config);
                    }

                    monitorConfig = config;
                }
            }
        }

        if (this.shouldInit()) {
            this.getObject();
        }

    }

在这一步其实就是的默认配置

consumer:dubbo:consumer 当reference某些属性没有配置的时候就可以采用默认配置

application:应用配置,用于配置当前应用信息

module:模块配置,用于配置当前模块信息,可选

registries:注册中心配置,用于配置连接注册中心相关信息

monitor:监控中心配置,用于配置连接监控中心相关信息,可选

方法的最后一行有一行 this.getObject(),调用FactoryBean的getObject方法,里面会调用ReferenceConfig的init方法进行数据组装,服务订阅,创建代理。

否则是在实际引用类时执行FactoryBean的getObject方法。

服务订阅

在getObject方法中如果代理对象未被创建值执行初始化 init()

public synchronized T get() {
        checkAndUpdateSubConfigs();

        if (destroyed) {
            throw new IllegalStateException("The invoker of ReferenceConfig(" + url + ") has already destroyed!");
        }
        if (ref == null) {
            init();
        }
        return ref;
    }

在初始化方法中先组装参数如下

private T createProxy(Map<String, String> map) {
        if (shouldJvmRefer(map)) {
            URL url = new URL(Constants.LOCAL_PROTOCOL, Constants.LOCALHOST_VALUE, 0, interfaceClass.getName()).addParameters(map);
            invoker = refprotocol.refer(interfaceClass, url);
            if (logger.isInfoEnabled()) {
                logger.info("Using injvm service " + interfaceClass.getName());
            }
        } else {
            if (url != null && url.length() > 0) { // user specified URL, could be peer-to-peer address, or register center's address.
                String[] us = Constants.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 (Constants.REGISTRY_PROTOCOL.equals(url.getProtocol())) {
                            urls.add(url.addParameterAndEncoded(Constants.REFER_KEY, StringUtils.toQueryString(map)));
                        } else {
                            urls.add(ClusterUtils.mergeUrl(url, map));
                        }
                    }
                }
            } else { // assemble URL from register center's configuration
                //配置中心初始化
                checkRegistry();
                List<URL> us = loadRegistries(false);
                if (CollectionUtils.isNotEmpty(us)) {
                    for (URL u : us) {
                        URL monitorUrl = loadMonitor(u);
                        if (monitorUrl != null) {
                            map.put(Constants.MONITOR_KEY, URL.encode(monitorUrl.toFullString()));
                        }
                        urls.add(u.addParameterAndEncoded(Constants.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 = refprotocol.refer(interfaceClass, urls.get(0));
            } else {
                List<Invoker<?>> invokers = new ArrayList<Invoker<?>>();
                URL registryURL = null;
                for (URL url : urls) {
                    invokers.add(refprotocol.refer(interfaceClass, url));
                    if (Constants.REGISTRY_PROTOCOL.equals(url.getProtocol())) {
                        registryURL = url; // use last registry url
                    }
                }
                if (registryURL != null) { // registry url is available
                    // use RegistryAwareCluster only when register's cluster is available
                    URL u = registryURL.addParameter(Constants.CLUSTER_KEY, RegistryAwareCluster.NAME);
                    // The invoker wrap relation would be: RegistryAwareClusterInvoker(StaticDirectory) -> FailoverClusterInvoker(RegistryDirectory, will execute route) -> 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()) {
            // make it possible for consumer to retry later if provider is temporarily unavailable
            initialized = false;
            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
         */
        MetadataReportService metadataReportService = null;
        if ((metadataReportService = getMetadataReportService()) != null) {
            URL consumerURL = new URL(Constants.CONSUMER_PROTOCOL, map.remove(Constants.REGISTER_IP_KEY), 0, map.get(Constants.INTERFACE_KEY), map);
            metadataReportService.publishConsumer(consumerURL);
        }
        // create service proxy
        return (T) proxyFactory.getProxy(invoker);
    }

在执行创建代理对象 ref = createProxy(map); 此方法主要做的事有

  1. 判断当前服务是本地服务还是远程服务,本地服务生成 InjvmInvoker
  2. 是否是用户指定URL调用,不是则检查注册表配置是否存在,然后将其转换为链接,如果是zookeeper则连接注册中心。
  3. loadRegistrie()根据注册中心装入 registry URl, 将zookeeper url协议更换为registry URl。
  4. 与注册中心进行交互,watch相应的节点

**

在方法 invoker = refprotocol.refer(interfaceClass, urls.get(0));

这段代码通过SPI机制获取到 Protocol 执行对象,执行过程是 ProtocolFilterWrapper → ProtocolListenerWrapper → RegistryProtocol

META-INF\dubbo\internal\org.apache.dubbo.rpc.Protocol

ProtocolFilterWrapper :过滤器调用链包装器

ProtocolListenerWrapper:监听器调用链包装器

RegistryProtocol:注册协议完成服务订阅

    private <T> Invoker<T> doRefer(Cluster cluster, Registry registry, Class<T> type, URL url) {
        RegistryDirectory<T> directory = new RegistryDirectory<T>(type, url);
        //将ZookeeperRegistry注入到RegistryDirectory中
        directory.setRegistry(registry);
        directory.setProtocol(protocol);
        // all attributes of REFER_KEY
        Map<String, String> parameters = new HashMap<String, String>(directory.getUrl().getParameters());
        //生成consumer端的URL协议,consumer://
        URL subscribeUrl = new URL(CONSUMER_PROTOCOL, parameters.remove(REGISTER_IP_KEY), 0, type.getName(), parameters);
        if (!ANY_VALUE.equals(url.getServiceInterface()) && url.getParameter(REGISTER_KEY, true)) {
            directory.setRegisteredConsumerUrl(getRegisteredConsumerUrl(subscribeUrl, url));
            //调用ZookeeperRegistry实例进行消费组地址注册
            registry.register(directory.getRegisteredConsumerUrl());
        }
        directory.buildRouterChain(subscribeUrl);
        //服务订阅
        directory.subscribe(subscribeUrl.addParameter(CATEGORY_KEY,
                PROVIDERS_CATEGORY + "," + CONFIGURATORS_CATEGORY + "," + ROUTERS_CATEGORY));

        Invoker invoker = cluster.join(directory);
        ProviderConsumerRegTable.registerConsumer(invoker, url, subscribeUrl, directory);
        return invoker;
    }

通过调用ZookeeperRegistry.doSubscribe方法实现消费者的地址注册和监听/dubbo/com.xxx.xxx/providers

最终调用 client.getChildren().usingWatcher(listener).forPath(path) 实现服务订阅

org.apache.dubbo.registry.integration.RegistryDirectory#notify 注册中心发生变化会触发此方法刷新本地注册表

创建代理对象

在配置初始化与订阅完成后,剩下的工作就是对服务接口进行包装,产生代理对象并返回。

*// create service proxy
*return (T) proxyFactory.getProxy(invoker);

Dubbo实现代理对象有两种方式,一种是JDK动态代理,使用的是JdkProxyFactory,另一种是使用Javassit字节码来实现,使用的是JavassistProxyFactory来实现,默认使用的是JavassistProxyFactory。

远程调用

前面是生成了ReferenceBean生成代理对象的流程,下面是如果通过代理对象进行方法的调用流程,从大的方面讲是代理调用,容错负载和远程通信。

执行过程

ReferenceAnnotationBeanPostProcessor →

InvokerInvocationHandler →

MockClusterInvoker →

FailoverClusterInvoker(负载均衡处理)

ListenerInvokerWrapper(监听器) →

ProtocolFilterWrapper(过滤器逻辑处理)

DubboInvoker(执行dubbo执行器)

HeaderExchangeChannel

请求方法

public ResponseFuture request(Object request, int timeout) throws RemotingException {
    if (closed) {
        throw new RemotingException(this.getLocalAddress(), null, "Failed to send request " + request + ", cause: The channel " + this + " is closed!");
    }
    //新建一个请求对象,构造方法会生成一个自增的唯一ID
    Request req = new Request();
    req.setVersion(Version.getProtocolVersion());
    req.setTwoWay(true);
    req.setData(request);
    //新建一个Future对象
    DefaultFuture future = DefaultFuture.newFuture(channel, req, timeout);
    try {
        //发送请求,进行远程调用
        channel.send(req);
    } catch (RemotingException e) {
        future.cancel();
        throw e;
    }
    //返回Future
    return future;
    }

看看DefaultFuture的get方法和receive方法

public Object get(int timeout) throws RemotingException {
        if (timeout <= 0) {
            timeout = Constants.DEFAULT_TIMEOUT;
        }
        //请求未返回时
        if (!isDone()) {
            long start = System.currentTimeMillis();
            //上锁
            lock.lock();
            try {
                while (!isDone()) {
                    //设置等待超时时间,请求返回时会唤醒
                    done.await(timeout, TimeUnit.MILLISECONDS);
                    if (isDone() || System.currentTimeMillis() - start > timeout) {
                        break;
                    }
                }
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            } finally {
                lock.unlock();
            }
            if (!isDone()) {
                throw new TimeoutException(sent > 0, channel, getTimeoutMessage(false));
            }
        }
        //获取返回值
        return returnFromResponse();
    }

private void doReceived(Response res) {
        //上锁
        lock.lock();
        try {
            response = res;
            if (done != null) {
                //环境线程
                done.signal();
            }
        } finally {
            lock.unlock();
        }
        if (callback != null) {
            invokeCallback(callback);
        }
    }

\