主頁 >  其他 > Dubbo學習記錄(五)-Dubbo與Spring的組態檔決議流程原理分析

Dubbo學習記錄(五)-Dubbo與Spring的組態檔決議流程原理分析

2022-03-04 07:52:46 其他

Dubbo與Spring的整合原理與流程分析

看Dubbo整合Spring的使用, 幾個注解就結束了,但是內部運作原理一概不知, 框架內部報錯,丟出例外都不知道是怎么回事, 最侄訓是決定花點時間看看dubbo的一些流程原始碼,

主要內容

看看Dubbo與Spring是如何做到無縫結合, 以及注解類是怎么被加載的,

  1. Dubbo中propertie?件決議以及處理流程原理
  2. Dubbo中@Service注解決議以及處理流程原理
  3. Dubbo中@Reference注解決議以及處理流程原理

啟動類

public class Application {
    public static void main(String[] args) throws Exception {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(ProviderConfiguration.class);
        context.start();
        System.in.read();
    }

    @Configuration
    @EnableDubbo(scanBasePackages = "org.apache.dubbo.demo.provider")
    @PropertySource("classpath:/spring/dubbo-provider.properties")
    static class ProviderConfiguration {
       
    }
}

兩個關鍵的注解:

  • @EnableDubbo注解:指定我們dubbo服務類的包路徑, 這些服務類是使用Dubbo服務的@Service注解修飾的服務類;
  • @PropertySource注解: 用來指定我們Dubbo組態檔的路徑, 然后通過@Value注解使用組態檔的內容,類似SpringBoot的application.properties檔案一樣被加載;

1. @EnableDubbo注解

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
@EnableDubboConfig
@DubboComponentScan
public @interface EnableDubbo {
	//省略一些方法
}

該注解上面有兩個關鍵的注解:

  1. EnableDubboConfig
    讀取properties組態檔, 并將配置轉換成一個個的配置Bean;
  2. DubboComponentScan
    掃描服務提供者和參考者類(即使用@Service修飾的類)

2. @EnableDubboConfig與@DubboComponentScan

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
@Import(DubboConfigConfigurationRegistrar.class)
public @interface EnableDubboConfig {

    /**
     * It indicates whether binding to multiple Spring Beans.
     *
     * @return the default value is <code>false</code>
     * @revised 2.5.9
     */
    boolean multiple() default true;

}

通過@Import注解,引入DubboConfigConfigurationRegistrar類, 將這個類轉換一個Bean注入容器, 另外, 還會使用這個類將所有的配置轉換成Bean注入容器;

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(DubboComponentScanRegistrar.class)
public @interface DubboComponentScan {
    String[] value() default {};
    String[] basePackages() default {};
    Class<?>[] basePackageClasses() default {};

}

通過@Import注解,引入DubboComponentScanRegistrar類, 將這個類轉換一個Bean注入容器, 另外, 還會使用這個類掃描所有的服務提供類,轉換成ServiceBean注入容器;

3. DubboConfigConfigurationRegistrar

  • 掃描配置類
public class DubboConfigConfigurationRegistrar implements ImportBeanDefinitionRegistrar {

    //

    @Override
    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
       //...省略部分代碼

        //獲取EnableDubboConfig的屬性值,有一個multiple
        AnnotationAttributes attributes = AnnotationAttributes.fromMap(
                importingClassMetadata.getAnnotationAttributes(EnableDubboConfig.class.getName()));

        //獲取multiple屬性的值
        boolean multiple = attributes.getBoolean("multiple");

        // Single Config Bindings
        registerBeans(registry, DubboConfigConfiguration.Single.class);

        if (multiple) { // Since 2.6.6 https://github.com/apache/dubbo/issues/3193
            registerBeans(registry, DubboConfigConfiguration.Multiple.class);
        }
    }
}
  1. 獲取EnableDubboConfig的所有屬性值;
  2. 獲取EnableDubboConfig的Multiple值;
  3. 注冊單例系結Bean;
  4. 注冊多例系結Bean;

當Spring啟動后, 肯定會通過AnnotationBeanDefinitionReader來執行registerBeanDefinitions方法的,(看了挺多博客, 都是這么說, Spring原始碼沒了解那么深);

3.1 DubboConfigConfiguration.Single類

    @EnableDubboConfigBindings({
            @EnableDubboConfigBinding(prefix = "dubbo.application", type = ApplicationConfig.class),
            @EnableDubboConfigBinding(prefix = "dubbo.module", type = ModuleConfig.class),
            @EnableDubboConfigBinding(prefix = "dubbo.registry", type = RegistryConfig.class),
            @EnableDubboConfigBinding(prefix = "dubbo.protocol", type = ProtocolConfig.class),
            @EnableDubboConfigBinding(prefix = "dubbo.monitor", type = MonitorConfig.class),
            @EnableDubboConfigBinding(prefix = "dubbo.provider", type = ProviderConfig.class),
            @EnableDubboConfigBinding(prefix = "dubbo.consumer", type = ConsumerConfig.class),
            @EnableDubboConfigBinding(prefix = "dubbo.config-center", type = ConfigCenterBean.class),
            @EnableDubboConfigBinding(prefix = "dubbo.metadata-report", type = MetadataReportConfig.class),
            @EnableDubboConfigBinding(prefix = "dubbo.metrics", type = MetricsConfig.class)
    })
    public static class Single {

    }

Single類 通過 @EnableDubboConfigBinding注解可以看出,根據Dubbo的配置前綴進行Bean型別的系結, 例如dubbo.application配置, 對應的型別是一個ApplicationConfig類的Bean;

3.2 DubboConfigConfiguration.Multiple

    /**
     * Multiple Dubbo {@link AbstractConfig Config} Bean Binding
     */
    @EnableDubboConfigBindings({
            @EnableDubboConfigBinding(prefix = "dubbo.applications", type = ApplicationConfig.class, multiple = true),
            @EnableDubboConfigBinding(prefix = "dubbo.modules", type = ModuleConfig.class, multiple = true),
            @EnableDubboConfigBinding(prefix = "dubbo.registries", type = RegistryConfig.class, multiple = true),
            @EnableDubboConfigBinding(prefix = "dubbo.protocols", type = ProtocolConfig.class, multiple = true),
            @EnableDubboConfigBinding(prefix = "dubbo.monitors", type = MonitorConfig.class, multiple = true),
            @EnableDubboConfigBinding(prefix = "dubbo.providers", type = ProviderConfig.class, multiple = true),
            @EnableDubboConfigBinding(prefix = "dubbo.consumers", type = ConsumerConfig.class, multiple = true),
            @EnableDubboConfigBinding(prefix = "dubbo.config-centers", type = ConfigCenterBean.class, multiple = true),
            @EnableDubboConfigBinding(prefix = "dubbo.metadata-reports", type = MetadataReportConfig.class, multiple = true),
            @EnableDubboConfigBinding(prefix = "dubbo.metricses", type = MetricsConfig.class, multiple = true)
    })
    public static class Multiple {

    }
  • Multiple類 通過 @EnableDubboConfigBinding注解可以看出,根據Dubbo的配置前綴進行Bean型別的系結, 例如dubbo.protocols配置多個協議, 而且每種協議都會轉換成一個型別為ProtocolConfig類的Bean,

  • 下面的例子,我就理解了:

#dubbo.protocol.name=dubbo
#dubbo.protocol.port=20881
#dubbo.protocol.host=0.0.0.0

dubbo.protocols.p1.name=dubbo
dubbo.protocols.p1.port=20880
dubbo.protocols.p1.host=0.0.0.0

dubbo.protocols.p2.name=dubbo
dubbo.protocols.p2.port=20881
dubbo.protocols.p2.host=0.0.0.0
  • dubbo.protocol.: 會生成單個Bean, Bean的型別是ProtocolConfig
  • dubbo.protocols: 會生成多個Bean, Bean的型別是ProtocolConfig, Bean的名稱與p1, p2有關

3.3 @EnableDubboConfigBindings注解

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(DubboConfigBindingsRegistrar.class)
public @interface EnableDubboConfigBindings {

    /**
     * The value of {@link EnableDubboConfigBindings}
     *
     * @return non-null
     */
    EnableDubboConfigBinding[] value();

}

  • value值是一個EnableDubboConfigBinding陣列
  • 通過@Import注解,匯入DubboConfigBindingsRegistrar.class類, 該類會獲取@EnableDubboConfigBindings注解中的value,也就是多個@EnableDubboConfigBinding注解,然后利用DubboConfigBindingRegistrar去處理這些@EnableDubboConfigBinding注解,

DubboConfigBindingsRegistrar

  • Spring啟動時, AnnotationBeanDefinitionReader來執行registerBeanDefinitions方法;
public class DubboConfigBindingsRegistrar implements ImportBeanDefinitionRegistrar, EnvironmentAware {

    private ConfigurableEnvironment environment;

    @Override
    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
        System.out.println("執行DubboConfigBindingsRegistrar");
        AnnotationAttributes attributes = AnnotationAttributes.fromMap(
                importingClassMetadata.getAnnotationAttributes(EnableDubboConfigBindings.class.getName()));

        // 拿到多個@EnableDubboConfigBinding注解
        AnnotationAttributes[] annotationAttributes = attributes.getAnnotationArray("value");

        DubboConfigBindingRegistrar registrar = new DubboConfigBindingRegistrar();
        registrar.setEnvironment(environment);

        for (AnnotationAttributes element : annotationAttributes) {

            // 逐個決議@EnableDubboConfigBinding注解,比如@EnableDubboConfigBinding(prefix = "dubbo.application", type = ApplicationConfig.class)
            registrar.registerBeanDefinitions(element, registry);

        }
    }
	//省略無關代碼;
}
  1. 獲取EnableDubboConfigBindings所有的屬性值
  2. 獲取EnableDubboConfigBindings的value屬性值;
  3. 創建配置系結注冊Bean工具類物件, 用來注冊一個個的配置Bean
  4. 遍歷回圈, 逐個決議@EnableDubboConfigBinding注解類;第一個引數事注解類資訊,第二個引數是Spring容器,方便將Bean注入容器;
DubboConfigBindingRegistrar

決議@EnableDubboConfigBinding注解類

public class DubboConfigBindingRegistrar implements ImportBeanDefinitionRegistrar, EnvironmentAware {

    private final Log log = LogFactory.getLog(getClass());

    private ConfigurableEnvironment environment;

    protected void registerBeanDefinitions(AnnotationAttributes attributes, BeanDefinitionRegistry registry) {

        // prefix = "dubbo.application"
        String prefix = environment.resolvePlaceholders(attributes.getString("prefix"));

        // type = ApplicationConfig.class
        Class<? extends AbstractConfig> configClass = attributes.getClass("type");

        boolean multiple = attributes.getBoolean("multiple");

        registerDubboConfigBeans(prefix, configClass, multiple, registry);

    }
}

作用:

  1. 獲取系結注解prefix屬性, 即配置的屬性dubbo.application
  2. 獲取系結注解type屬性, 是每一中配置對應的型別Class資訊;
  3. 獲取系結注解multiple屬性
  4. 根據prefix, type, multipart生成Bean注入容器registry;
    private void registerDubboConfigBeans(String prefix,
                                          Class<? extends AbstractConfig> configClass,
                                          boolean multiple,
                                          BeanDefinitionRegistry registry) {

        // 從properties檔案中根據前綴拿對應的配置項,比如根據dubbo.application前綴,
        // 就可以拿到:
        // dubbo.application.name=dubbo-demo-provider-application
        // dubbo.application.logger=log4j
        Map<String, Object> properties = getSubProperties(environment.getPropertySources(), prefix);

        // 如果沒有相關的配置項,則不需要注冊BeanDefinition
        if (CollectionUtils.isEmpty(properties)) {
            if (log.isDebugEnabled()) {
                log.debug("There is no property for binding to dubbo config class [" + configClass.getName()
                        + "] within prefix [" + prefix + "]");
            }
            return;
        }

        // 根據配置項生成beanNames,為什么會有多個?
        // 普通情況一個dubbo.application前綴對應一個ApplicationConfig型別的Bean
        // 特殊情況下,比如dubbo.protocols對應了:
//        dubbo.protocols.p1.name=dubbo
//        dubbo.protocols.p1.port=20880
//        dubbo.protocols.p1.host=0.0.0.0

//        dubbo.protocols.p2.name=http
//        dubbo.protocols.p2.port=8082
//        dubbo.protocols.p2.host=0.0.0.0
        // 那么就需要對應兩個ProtocolConfig型別的Bean,那么就需要兩個beanName:p1和p2

        // 這里就是multiple為true或false的區別,名字的區別,根據multiple用來判斷是否從配置項中獲取beanName
        // 如果multiple為false,則看有沒有配置id屬性,如果沒有配置則自動生成一個beanName.
        Set<String> beanNames = multiple ? resolveMultipleBeanNames(properties) :
                Collections.singleton(resolveSingleBeanName(properties, configClass, registry));

        for (String beanName : beanNames) {

            // 為每個beanName,注冊一個空的BeanDefinition
            registerDubboConfigBean(beanName, configClass, registry);

            // 為每個bean注冊一個DubboConfigBindingBeanPostProcessor的Bean后置處理器
            registerDubboConfigBindingBeanPostProcessor(prefix, beanName, multiple, registry);

        }

        // 注冊一個NamePropertyDefaultValueDubboConfigBeanCustomizer的bean
        registerDubboConfigBeanCustomizers(registry);

    }

作業:

  1. getSubProperties:獲取propertis資訊中,包含了系結注解前綴prefix的配置
  2. resolveMultipleBeanNames | resolveSingleBeanName: 生成注入容器的Bean的名稱;
  3. 遍歷生成的Bean名稱;
    3.1 registerDubboConfigBean為每個Bean名稱注入一個空的BeanDefinition物件
    3.2 registerDubboConfigBindingBeanPostProcessor為每個Bean注冊一個DubboConfigBindingBeanPostProcessor后置處理器;
  4. registerDubboConfigBeanCustomizers:注冊一個NamePropertyDefaultValueDubboConfigBeanCustomizer的bean
  • getSubProperties(Iterable<PropertySource<?>> propertySources, String prefix)
	//主要:1. propertySources轉化轉換為AbstractEnvironment 物件
    public static Map<String, Object> getSubProperties(Iterable<PropertySource<?>> propertySources, String prefix) {
        // Non-Extension AbstractEnvironment
        AbstractEnvironment environment = new AbstractEnvironment() {
        };
        MutablePropertySources mutablePropertySources = environment.getPropertySources();
        for (PropertySource<?> source : propertySources) {
            mutablePropertySources.addLast(source);
        }
        return getSubProperties(environment, prefix);
    }
    //1. 獲取所有環境配置
    //2. normalizePrefix生成系結 前綴字串 prefix+"." , 多了一個點;
    //3. 遍歷回圈所有配置
    //3.1 找到所有前綴字串開頭的 配置項
    //3.2 name.substring(normalizedPrefix.length())截取字串, 前綴字串后面的內容全部截取下來;
    //3.3 獲取前綴字串配置項對應的值;
    //3.4 subProperties.put(subName, value)將結果放入容器中subProperties 
    public static Map<String, Object> getSubProperties(ConfigurableEnvironment environment, String prefix) {

        Map<String, Object> subProperties = new LinkedHashMap<>();

        MutablePropertySources propertySources = environment.getPropertySources();

        String normalizedPrefix = normalizePrefix(prefix);

        for (PropertySource<?> source : propertySources) {
            if (source instanceof EnumerablePropertySource) {
                for (String name : ((EnumerablePropertySource<?>) source).getPropertyNames()) {
                    if (!subProperties.containsKey(name) && name.startsWith(normalizedPrefix)) {
                        String subName = name.substring(normalizedPrefix.length());
                        if (!subProperties.containsKey(subName)) { // take first one
                            Object value = source.getProperty(name);
                            if (value instanceof String) {
                                // Resolve placeholder
                                value = environment.resolvePlaceholders((String) value);
                            }
                            subProperties.put(subName, value);
                        }
                    }
                }
            }
        }

        return Collections.unmodifiableMap(subProperties);

    }
    
    
  • resolveMultipleBeanNames(properties)
    獲取Multiple下的bean名稱;
	//1. 創建一個Set集合, 作用是用來去重
	//2. 遍歷前綴對應的所有配置項的Key;
	//3. 獲取"."號出現的問題的位置;
	//4. 將Bean的名稱放入Set集合,相同就去重;
    private Set<String> resolveMultipleBeanNames(Map<String, Object> properties) {

        Set<String> beanNames = new LinkedHashSet<String>();

        // 比如dubbo.protocols.p1.name=dubbo的propertyName為p1.name

        for (String propertyName : properties.keySet()) {

            // propertyName為p1.name
            int index = propertyName.indexOf(".");

            if (index > 0) {

                // 截取beanName名字為p1
                String beanName = propertyName.substring(0, index);

                beanNames.add(beanName);
            }

        }

        return beanNames;
    }
  • resolveSingleBeanName(properties, configClass, registry)
    獲取single配置的Bean名稱;
	//1. 獲取id的值;
	//2. id值為空,自動生成一個Bean的名稱;
	//3. Id值不為空,就用來當作bean的名稱,回傳;
    private String resolveSingleBeanName(Map<String, Object> properties, Class<? extends AbstractConfig> configClass,
                                         BeanDefinitionRegistry registry) {

        // 配置了dubbo.application.id=appl,那么appl就是beanName
        String beanName = (String) properties.get("id");
        // 如果beanName為null,則會進入if分支,由spring自動生成一個beanName,比如org.apache.dubbo.config.ApplicationConfig#0
        if (!StringUtils.hasText(beanName)) {
            BeanDefinitionBuilder builder = rootBeanDefinition(configClass);
            beanName = BeanDefinitionReaderUtils.generateBeanName(builder.getRawBeanDefinition(), registry);
        }

        return beanName;

    }

  • registerDubboConfigBean(beanName, configClass, registry)
    創建一個空的BeanDefinition類,并放入IOC容器
	//1. 創建BeanDefinitionBuilder構造類實體;
	//2. 獲取一個BeanDefinition類的實體;
	//3. 根據已經生成bean名稱,空的BeanDefinition實體, 注入IOC容器中;
    private void registerDubboConfigBean(String beanName, Class<? extends AbstractConfig> configClass,
                                         BeanDefinitionRegistry registry) {

        BeanDefinitionBuilder builder = rootBeanDefinition(configClass);

        AbstractBeanDefinition beanDefinition = builder.getBeanDefinition();

        registry.registerBeanDefinition(beanName, beanDefinition);   // ApplicatinoConfig物件

        if (log.isInfoEnabled()) {
            log.info("The dubbo config bean definition [name : " + beanName + ", class : " + configClass.getName() +
                    "] has been registered.");
        }

    }
  • registerDubboConfigBindingBeanPostProcessor(prefix, beanName, multiple, registry)
    創建一個DubboConfigBindingBeanPostProcessor后置處理器, 并注入容器;
	//1. 創建DubboConfigBindingBeanPostProcessor的一個BeanDefinitionBuilder構建物件;
	//2. 獲取真實前綴, 如果Multiple為true, 則是dubbo.protocols.p1, 為false, 則是dubbo.protocol;
	//3. 添加兩個構造方法引數;
	//4. 創建一個空的DubboConfigBindingBeanPostProcessor的BeanDefinition物件;
	//5. 生成DubboConfigBindingBeanPostProcessor的bean名稱為key, 空BeanDefinition實體注入容器;
    private void registerDubboConfigBindingBeanPostProcessor(String prefix, String beanName, boolean multiple,
                                                             BeanDefinitionRegistry registry) {

        // 注冊一個DubboConfigBindingBeanPostProcessor的Bean
        // 每個XxConfig的Bean對應一個DubboConfigBindingBeanPostProcessor的Bean
        // 比如,一個ApplicationConfig對應一個DubboConfigBindingBeanPostProcessor,
        // 一個ProtocolConfig也會對應一個DubboConfigBindingBeanPostProcessor
        // 在構造DubboConfigBindingBeanPostProcessor的時候會指定構造方法的值,這樣就可以區別開來了

        Class<?> processorClass = DubboConfigBindingBeanPostProcessor.class;

        BeanDefinitionBuilder builder = rootBeanDefinition(processorClass);

        // 真實的前綴,比如dubbo.registries.r2
        String actualPrefix = multiple ? normalizePrefix(prefix) + beanName : prefix;

        // 添加兩個構造方法引數值,所以會呼叫DubboConfigBindingBeanPostProcessor的兩個引數的構造方法
        builder.addConstructorArgValue(actualPrefix).addConstructorArgValue(beanName);

        AbstractBeanDefinition beanDefinition = builder.getBeanDefinition();

        beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);

        registerWithGeneratedName(beanDefinition, registry);

        if (log.isInfoEnabled()) {
            log.info("The BeanPostProcessor bean definition [" + processorClass.getName()
                    + "] for dubbo config bean [name : " + beanName + "] has been registered.");
        }

    }
    
    public static String registerWithGeneratedName(AbstractBeanDefinition definition, BeanDefinitionRegistry registry) throws BeanDefinitionStoreException {
        String generatedName = generateBeanName(definition, registry, false);
        registry.registerBeanDefinition(generatedName, definition);
        return generatedName;
    }
    //
    public static String generateBeanName(BeanDefinition definition, BeanDefinitionRegistry registry, boolean isInnerBean) throws BeanDefinitionStoreException {
        //獲取BeanDefinition 的 beanName;
        String generatedBeanName = definition.getBeanClassName();
		//...省略部分代碼
        if (!StringUtils.hasText(generatedBeanName)) {
   		//例外處理
        } else {
            String id = generatedBeanName;
            if (isInnerBean) {
                id = generatedBeanName + "#" + ObjectUtils.getIdentityHexString(definition);
            } else {
            	//判斷存在多少id為generatedBeanName, 如果有count自增1, 最后容器不包含
            	//generatedBeanName + "#" + counter的bean名稱時,就是用這個組合字串作為Bean名稱;
                for(int counter = -1; counter == -1 || registry.containsBeanDefinition(id); id = generatedBeanName + "#" + counter) {
                    ++counter;
                }
            }

            return id;
        }
    }

3. registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry)

注冊各個Dubbo配置Bean到容器中;

 
public class DubboConfigConfigurationRegistrar implements ImportBeanDefinitionRegistrar {

    //

    @Override
    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
        System.out.println("執行DubboConfigConfigurationRegistrar");

        //獲取EnableDubboConfig的屬性值,有一個multiple
        AnnotationAttributes attributes = AnnotationAttributes.fromMap(
                importingClassMetadata.getAnnotationAttributes(EnableDubboConfig.class.getName()));

        //獲取multiple屬性的值
        boolean multiple = attributes.getBoolean("multiple");

        // Single Config Bindings
        registerBeans(registry, DubboConfigConfiguration.Single.class);

        if (multiple) { // Since 2.6.6 https://github.com/apache/dubbo/issues/3193
            registerBeans(registry, DubboConfigConfiguration.Multiple.class);
        }
    }

}

回到開頭的第3步驟;

4. registerBeans(registry, DubboConfigConfiguration.Multiple.class)

Spring中的AnnotatedBeanDefinitionReader來決議annotatedClasses會決議該類上的注解,然后進行處理

	// annotatedClasses 引數值為 :  DubboConfigConfiguration.Single.class,
	// DubboConfigConfiguration.Multiple.class;
	//作用:
	//1. annotatedClasses轉換為迭代器;
	//2. 遍歷迭代器,判斷容器中是否已經存在這個Bean類
	//如果存在就在這個Bean從迭代器中去掉;
	//isPresentBean(registry, annotatedClass)
	//3. 創建一個AnnotatedBeanDefinitionReader物件實體;
	//4. Spring中的AnnotatedBeanDefinitionReader來決議annotatedClasses,
	//會決議該類上的注解,然后進行處理(Spring的內容)
    public static void registerBeans(BeanDefinitionRegistry registry, Class<?>... annotatedClasses) {
        if (ObjectUtils.isEmpty(annotatedClasses)) {
            return;
        }

        // Remove all annotated-classes that have been registered
        Iterator<Class<?>> iterator = new ArrayList<>(asList(annotatedClasses)).iterator();

        while (iterator.hasNext()) {
            Class<?> annotatedClass = iterator.next();
            if (isPresentBean(registry, annotatedClass)) {
                iterator.remove();
            }
        }

        AnnotatedBeanDefinitionReader reader = new AnnotatedBeanDefinitionReader(registry);

        if (logger.isDebugEnabled()) {
            logger.debug(registry.getClass().getSimpleName() + " will register annotated classes : " + asList(annotatedClasses) + " .");
        }
        // 利用Spring中的AnnotatedBeanDefinitionReader來決議annotatedClasses
        // 會決議該類上的注解,然后進行處理
        reader.register(annotatedClasses);

    }

總結

@EnableDubboConfig注解的作用就是通過DubboConfigConfigurationRegistrar 決議組態檔里面所有的dubbo配置項,

  1. 通過AnnotatedBeanDefinitionReader來決議Multiple/Single型別上的EnableDubboConfigBindings的值(是一個@EnableDubboConfigBinding陣列)
  2. 讀取組態檔中Dubbo的所有配置項,根據@EnableDubboConfigBinding系結注解的prefix前綴,匹配配置項的key, 然后將單個配置項,或者一組配置項轉換成一個個type型別Class的BeanDefinition的Bean, 注入IOC容器;
  3. 然后每個XxConfig的Bean會生成對應一個DubboConfigBindingBeanPostProcessor的Bean注入IOC容器

轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/437034.html

標籤:其他

上一篇:Hadoop之環境配置

下一篇:精心整理:Spark關鍵字知識點

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • 網閘典型架構簡述

    網閘架構一般分為兩種:三主機的三系統架構網閘和雙主機的2+1架構網閘。 三主機架構分別為內端機、外端機和仲裁機。三機無論從軟體和硬體上均各自獨立。首先從硬體上來看,三機都用各自獨立的主板、記憶體及存盤設備。從軟體上來看,三機有各自獨立的作業系統。這樣能達到完全的三機獨立。對于“2+1”系統,“2”分為 ......

    uj5u.com 2020-09-10 02:00:44 more
  • 如何從xshell上傳檔案到centos linux虛擬機里

    如何從xshell上傳檔案到centos linux虛擬機里及:虛擬機CentOs下執行 yum -y install lrzsz命令,出現錯誤:鏡像無法找到軟體包 前言 一、安裝lrzsz步驟 二、上傳檔案 三、遇到的問題及解決方案 總結 前言 提示:其實很簡單,往虛擬機上安裝一個上傳檔案的工具 ......

    uj5u.com 2020-09-10 02:00:47 more
  • 一、SQLMAP入門

    一、SQLMAP入門 1、判斷是否存在注入 sqlmap.py -u 網址/id=1 id=1不可缺少。當注入點后面的引數大于兩個時。需要加雙引號, sqlmap.py -u "網址/id=1&uid=1" 2、判斷文本中的請求是否存在注入 從文本中加載http請求,SQLMAP可以從一個文本檔案中 ......

    uj5u.com 2020-09-10 02:00:50 more
  • Metasploit 簡單使用教程

    metasploit 簡單使用教程 浩先生, 2020-08-28 16:18:25 分類專欄: kail 網路安全 linux 文章標簽: linux資訊安全 編輯 著作權 metasploit 使用教程 前言 一、Metasploit是什么? 二、準備作業 三、具體步驟 前言 Msfconsole ......

    uj5u.com 2020-09-10 02:00:53 more
  • 游戲逆向之驅動層與用戶層通訊

    驅動層代碼: #pragma once #include <ntifs.h> #define add_code CTL_CODE(FILE_DEVICE_UNKNOWN,0x800,METHOD_BUFFERED,FILE_ANY_ACCESS) /* 更多游戲逆向視頻www.yxfzedu.com ......

    uj5u.com 2020-09-10 02:00:56 more
  • 北斗電力時鐘(北斗授時服務器)讓網路資料更精準

    北斗電力時鐘(北斗授時服務器)讓網路資料更精準 北斗電力時鐘(北斗授時服務器)讓網路資料更精準 京準電子科技官微——ahjzsz 近幾年,資訊技術的得了快速發展,互聯網在逐漸普及,其在人們生活和生產中都得到了廣泛應用,并且取得了不錯的應用效果。計算機網路資訊在電力系統中的應用,一方面使電力系統的運行 ......

    uj5u.com 2020-09-10 02:01:03 more
  • 【CTF】CTFHub 技能樹 彩蛋 writeup

    ?碎碎念 CTFHub:https://www.ctfhub.com/ 筆者入門CTF時時剛開始刷的是bugku的舊平臺,后來才有了CTFHub。 感覺不論是網頁UI設計,還是題目質量,賽事跟蹤,工具軟體都做得很不錯。 而且因為獨到的金幣制度的確讓人有一種想去刷題賺金幣的感覺。 個人還是非常喜歡這個 ......

    uj5u.com 2020-09-10 02:04:05 more
  • 02windows基礎操作

    我學到了一下幾點 Windows系統目錄結構與滲透的作用 常見Windows的服務詳解 Windows埠詳解 常用的Windows注冊表詳解 hacker DOS命令詳解(net user / type /md /rd/ dir /cd /net use copy、批處理 等) 利用dos命令制作 ......

    uj5u.com 2020-09-10 02:04:18 more
  • 03.Linux基礎操作

    我學到了以下幾點 01Linux系統介紹02系統安裝,密碼啊破解03Linux常用命令04LAMP 01LINUX windows: win03 8 12 16 19 配置不繁瑣 Linux:redhat,centos(紅帽社區版),Ubuntu server,suse unix:金融機構,證券,銀 ......

    uj5u.com 2020-09-10 02:04:30 more
  • 05HTML

    01HTML介紹 02頭部標簽講解03基礎標簽講解04表單標簽講解 HTML前段語言 js1.了解代碼2.根據代碼 懂得挖掘漏洞 (POST注入/XSS漏洞上傳)3.黑帽seo 白帽seo 客戶網站被黑帽植入劫持代碼如何處理4.熟悉html表單 <html><head><title>TDK標題,描述 ......

    uj5u.com 2020-09-10 02:04:36 more
最新发布
  • 2023年最新微信小程式抓包教程

    01 開門見山 隔一個月發一篇文章,不過分。 首先回顧一下《微信系結手機號資料庫被脫庫事件》,我也是第一時間得知了這個訊息,然后跟蹤了整件事情的經過。下面是這起事件的相關截圖以及近日流出的一萬條資料樣本: 個人認為這件事也沒什么,還不如關注一下之前45億快遞資料查詢渠道疑似在近日復活的訊息。 訊息是 ......

    uj5u.com 2023-04-20 08:48:24 more
  • web3 產品介紹:metamask 錢包 使用最多的瀏覽器插件錢包

    Metamask錢包是一種基于區塊鏈技術的數字貨幣錢包,它允許用戶在安全、便捷的環境下管理自己的加密資產。Metamask錢包是以太坊生態系統中最流行的錢包之一,它具有易于使用、安全性高和功能強大等優點。 本文將詳細介紹Metamask錢包的功能和使用方法。 一、 Metamask錢包的功能 數字資 ......

    uj5u.com 2023-04-20 08:47:46 more
  • vulnhub_Earth

    前言 靶機地址->>>vulnhub_Earth 攻擊機ip:192.168.20.121 靶機ip:192.168.20.122 參考文章 https://www.cnblogs.com/Jing-X/archive/2022/04/03/16097695.html https://www.cnb ......

    uj5u.com 2023-04-20 07:46:20 more
  • 從4k到42k,軟體測驗工程師的漲薪史,給我看哭了

    清明節一過,盲猜大家已經無心上班,在數著日子準備過五一,但一想到銀行卡里的余額……瞬間心情就不美麗了。最近,2023年高校畢業生就業調查顯示,本科畢業月平均起薪為5825元。調查一出,便有很多同學表示自己又被平均了。看著這一資料,不免讓人想到前不久中國青年報的一項調查:近六成大學生認為畢業10年內會 ......

    uj5u.com 2023-04-20 07:44:00 more
  • 最新版本 Stable Diffusion 開源 AI 繪畫工具之中文自動提詞篇

    🎈 標簽生成器 由于輸入正向提示詞 prompt 和反向提示詞 negative prompt 都是使用英文,所以對學習母語的我們非常不友好 使用網址:https://tinygeeker.github.io/p/ai-prompt-generator 這個網址是為了讓大家在使用 AI 繪畫的時候 ......

    uj5u.com 2023-04-20 07:43:36 more
  • 漫談前端自動化測驗演進之路及測驗工具分析

    隨著前端技術的不斷發展和應用程式的日益復雜,前端自動化測驗也在不斷演進。隨著 Web 應用程式變得越來越復雜,自動化測驗的需求也越來越高。如今,自動化測驗已經成為 Web 應用程式開發程序中不可或缺的一部分,它們可以幫助開發人員更快地發現和修復錯誤,提高應用程式的性能和可靠性。 ......

    uj5u.com 2023-04-20 07:43:16 more
  • CANN開發實踐:4個DVPP記憶體問題的典型案例解讀

    摘要:由于DVPP媒體資料處理功能對存放輸入、輸出資料的記憶體有更高的要求(例如,記憶體首地址128位元組對齊),因此需呼叫專用的記憶體申請介面,那么本期就分享幾個關于DVPP記憶體問題的典型案例,并給出原因分析及解決方法。 本文分享自華為云社區《FAQ_DVPP記憶體問題案例》,作者:昇騰CANN。 DVPP ......

    uj5u.com 2023-04-20 07:43:03 more
  • msf學習

    msf學習 以kali自帶的msf為例 一、msf核心模塊與功能 msf模塊都放在/usr/share/metasploit-framework/modules目錄下 1、auxiliary 輔助模塊,輔助滲透(埠掃描、登錄密碼爆破、漏洞驗證等) 2、encoders 編碼器模塊,主要包含各種編碼 ......

    uj5u.com 2023-04-20 07:42:59 more
  • Halcon軟體安裝與界面簡介

    1. 下載Halcon17版本到到本地 2. 雙擊安裝包后 3. 步驟如下 1.2 Halcon軟體安裝 界面分為四大塊 1. Halcon的五個助手 1) 影像采集助手:與相機連接,設定相機引數,采集影像 2) 標定助手:九點標定或是其它的標定,生成標定檔案及內參外參,可以將像素單位轉換為長度單位 ......

    uj5u.com 2023-04-20 07:42:17 more
  • 在MacOS下使用Unity3D開發游戲

    第一次發博客,先發一下我的游戲開發環境吧。 去年2月份買了一臺MacBookPro2021 M1pro(以下簡稱mbp),這一年來一直在用mbp開發游戲。我大致分享一下我的開發工具以及使用體驗。 1、Unity 官網鏈接: https://unity.cn/releases 我一般使用的Apple ......

    uj5u.com 2023-04-20 07:40:19 more