• dubbo 3.2.0 consumer bean初始化及服务发现简记


    consumer bean初始化

    以spring 如下配置
    
    • 1
    <dubbo:reference id="versionConsumerBean" interface="org.apache.dubbo.samples.version.api.VersionService" version="*"/>
    
    • 1

    为例,先使用spring 的初始化,核心代码

     try {
                    final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
                    checkMergedBeanDefinition(mbd, beanName, args);
    
                    // Guarantee initialization of beans that the current bean depends on.
                    String[] dependsOn = mbd.getDependsOn();
                    if (dependsOn != null) {
                        for (String dep : dependsOn) {
                            if (isDependent(beanName, dep)) {
                                throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                                        "Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");
                            }
                            registerDependentBean(dep, beanName);
                            try {
                                getBean(dep);
                            }
                            catch (NoSuchBeanDefinitionException ex) {
                                throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                                        "'" + beanName + "' depends on missing bean '" + dep + "'", ex);
                            }
                        }
                    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    初始化为class org.apache.dubbo.config.spring.ReferenceBean。

    然后在类似如下代码

    VersionService versionService = (VersionService) context.getBean("versionConsumerBean");
    
    • 1

    处进行了二次变化,创建LazyProxy
    在这里插入图片描述

    核心代码在ReferenceBean的getObject,代码如下:
     /**
         * Create bean instance.
         *
         * 

    * Why we need a lazy proxy? * *

    * When Spring searches beans by type, if Spring cannot determine the type of a factory bean, it may try to initialize it. * The ReferenceBean is also a FactoryBean. *
    * (This has already been resolved by decorating the BeanDefinition: {@link DubboBeanDefinitionParser#configReferenceBean}) * *

    * In addition, if some ReferenceBeans are dependent on beans that are initialized very early, * and dubbo config beans are not ready yet, there will be many unexpected problems if initializing the dubbo reference immediately. * *

    * When it is initialized, only a lazy proxy object will be created, * and dubbo reference-related resources will not be initialized. *
    * In this way, the influence of Spring is eliminated, and the dubbo configuration initialization is controllable. * * * @see DubboConfigBeanInitializer * @see ReferenceBeanManager#initReferenceBean(ReferenceBean) * @see DubboBeanDefinitionParser#configReferenceBean */ @Override public T getObject() { if (lazyProxy == null) { createLazyProxy(); } return (T) lazyProxy; }

    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35

    变换后返回的是一个aop java对象了。
    在这里插入图片描述

    服务发现

    dubbo 的服务调用是proxy通invoker实现,因此核心过程就在如下函数中。

    @SuppressWarnings({"unchecked"})
    private T createProxy(Map<String, String> referenceParameters) {
        urls.clear();
    
        meshModeHandleUrl(referenceParameters);
    
        if (StringUtils.isNotEmpty(url)) {
            // user specified URL, could be peer-to-peer address, or register center's address.
            parseUrl(referenceParameters);
        } else {
            // if protocols not in jvm checkRegistry
            aggregateUrlFromRegistry(referenceParameters);
        }
        createInvoker();
    
        if (logger.isInfoEnabled()) {
            logger.info("Referred dubbo service: [" + referenceParameters.get(INTERFACE_KEY) + "]." +
                    (Boolean.parseBoolean(referenceParameters.get(GENERIC_KEY)) ?
                            " it's GenericService reference" : " it's not GenericService reference"));
        }
    
        URL consumerUrl = new ServiceConfigURL(CONSUMER_PROTOCOL, referenceParameters.get(REGISTER_IP_KEY), 0,
                referenceParameters.get(INTERFACE_KEY), referenceParameters);
        consumerUrl = consumerUrl.setScopeModel(getScopeModel());
        consumerUrl = consumerUrl.setServiceModel(consumerModel);
        MetadataUtils.publishServiceDefinition(consumerUrl, consumerModel.getServiceModel(), getApplicationModel());
    
        // create service proxy
        return (T) proxyFactory.getProxy(invoker, ProtocolUtils.isGeneric(generic));
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30

    在创建proxy的过程中,可以多次看到TargetService和protocolServiceKey的处理,核心是找到两者批量的service
    在这里插入图片描述
    核心比较代码如下

    public static boolean isMatch(URL consumerUrl, URL providerUrl) {
        String consumerInterface = consumerUrl.getServiceInterface();
        String providerInterface = providerUrl.getServiceInterface();
        if (!"*".equals(consumerInterface) && !"*".equals(providerInterface) && !StringUtils.isEquals(consumerInterface, providerInterface)) {
            return false;
        } else if (!isMatchCategory(providerUrl.getCategory("providers"), consumerUrl.getCategory("providers"))) {
            return false;
        } else if (!providerUrl.getParameter("enabled", true) && !"*".equals(consumerUrl.getParameter("enabled"))) {
            return false;
        } else {
            String consumerGroup = consumerUrl.getGroup();
            String consumerVersion = consumerUrl.getVersion();
            String consumerClassifier = consumerUrl.getParameter("classifier", "*");
            String providerGroup = providerUrl.getGroup();
            String providerVersion = providerUrl.getVersion();
            String providerClassifier = providerUrl.getParameter("classifier", "*");
            boolean groupMatches = "*".equals(consumerGroup) || StringUtils.isEquals(consumerGroup, providerGroup) || StringUtils.isContains(consumerGroup, providerGroup);
            boolean versionMatches = "*".equals(consumerVersion) || StringUtils.isEquals(consumerVersion, providerVersion);
            boolean classifierMatches = consumerClassifier == null || "*".equals(consumerClassifier) || StringUtils.isEquals(consumerClassifier, providerClassifier);
            return groupMatches && versionMatches && classifierMatches;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    注意看最后几段boolean的match,即

    1. group
    2. version
    3. class(interface)

    要匹配

    invoker 是在服务发现后依次进行router-cluster-failover 判定后进行调用,可以参考下图

    在这里插入图片描述
    而服务发现(以zk为例),核心用到以下类
    在这里插入图片描述

    zk 数据结构

    dubbo root

    [zk: localhost:2181(CONNECTED) 23] ls /dubbo
    [config, mapping, metadata, org.apache.dubbo.metadata.MetadataService, org.apache.dubbo.mock.api.MockService, org.apache.dubbo.samples.version.api.VersionService]
    
    • 1
    • 2

    provider创建时候负责写入zk的providers

    
    [zk: localhost:2181(CONNECTED) 24] ls /dubbo/org.apache.dubbo.samples.version.api.VersionService
    [configurators, providers]
    
    • 1
    • 2
    • 3

    providers可以有多版本

    [zk: localhost:2181(CONNECTED) 25] ls /dubbo/org.apache.dubbo.samples.version.api.VersionService/providers
    [dubbo%3A%2F%2F192.168.3.28%3A20880%2Forg.apache.dubbo.samples.version.api.VersionService%3Fanyhost%3Dtrue%26application%3Dversion-provider%26background%3Dfalse%26deprecated%3Dfalse%26dubbo%3D2.0.2%26dynamic%3Dtrue%26executor-management-mode%3Disolation%26file-cache%3Dtrue%26generic%3Dfalse%26interface%3Dorg.apache.dubbo.samples.version.api.VersionService%26methods%3DsayHello%26pid%3D8804%26prefer.serialization%3Dfastjson2%2Chessian2%26release%3D3.2.0%26revision%3D1.0.0%26service-name-mapping%3Dtrue%26side%3Dprovider%26timestamp%3D1685160190088%26token%3Db4d3e756-3a85-40ab-b3fd-c4b1352879ce%26version%3D1.0.0, dubbo%3A%2F%2F192.168.3.28%3A20880%2Forg.apache.dubbo.samples.version.api.VersionService%3Fanyhost%3Dtrue%26application%3Dversion-provider%26background%3Dfalse%26deprecated%3Dfalse%26dubbo%3D2.0.2%26dynamic%3Dtrue%26executor-management-mode%3Disolation%26file-cache%3Dtrue%26generic%3Dfalse%26interface%3Dorg.apache.dubbo.samples.version.api.VersionService%26methods%3DsayHello%26pid%3D8804%26prefer.serialization%3Dfastjson2%2Chessian2%26release%3D3.2.0%26revision%3D2.0.0%26service-name-mapping%3Dtrue%26side%3Dprovider%26timestamp%3D1685160186753%26token%3Dbc2534d5-f980-4a41-ab90-e4e9ae688ad9%26version%3D2.0.0]
    
    • 1
    • 2

    完整的service下目录

    [zk: localhost:2181(CONNECTED) 7] ls -s /dubbo/org.apache.dubbo.samples.version.api.VersionService
    [configurators, consumers, providers, routers]
    
    • 1
    • 2
  • 相关阅读:
    MySQL题外篇【ORM思想解析】
    Java进阶篇--LockSupport
    单因素方差分析(one-way analysis of variance)【R实现,用例题帮你更好理解】
    B树、B+树和B*树
    RC4算法:流密码算法的经典之作
    如何在Excel中自动创建报告 Excel中自动创建报告的方法
    最大网络流算法之dinic算法
    通关GO语言22 网络编程:Go 语言如何通过 RPC 实现跨平台服务?
    Tensorflow C++部署实战-linux平台上cuda环境搭建(1)
    java毕业设计开题报告springboot+mysql实现的电影资讯网站|影视[包运行成功]
  • 原文地址:https://blog.csdn.net/weixin_40455124/article/details/130909113