• Dubbo中@EnableDubbo注解原理


    前言

    前面解析过很多@EnableXXX注解开启某个功能的原理,其注解内部都是通过@Import注解,来引入一个类,通过这个类,将开启功能的核心类引入spring容器,并进行一系列初始化操作。@EnableDubbo注解也不例外,还是这个套路,下面看其详细实现。

    @EnableDubbo原理解析

    点进去,看其源码:

    @Target({ElementType.TYPE})
    @Retention(RetentionPolicy.RUNTIME)
    @Inherited
    @Documented
    @EnableDubboConfig
    @DubboComponentScan
    public @interface EnableDubbo {
    
        /**
         * Base packages to scan for annotated @Service classes.
         * <p>
         * Use {@link #scanBasePackageClasses()} for a type-safe alternative to String-based
         * package names.
         *
         * @return the base packages to scan
         * @see DubboComponentScan#basePackages()
         */
        @AliasFor(annotation = DubboComponentScan.class, attribute = "basePackages")
        String[] scanBasePackages() default {};
    
        /**
         * Type-safe alternative to {@link #scanBasePackages()} for specifying the packages to
         * scan for annotated @Service classes. The package of each class specified will be
         * scanned.
         *
         * @return classes from the base packages to scan
         * @see DubboComponentScan#basePackageClasses
         */
        @AliasFor(annotation = DubboComponentScan.class, attribute = "basePackageClasses")
        Class<?>[] scanBasePackageClasses() default {};
    
    
        /**
         * It indicates whether {@link AbstractConfig} binding to multiple Spring Beans.
         *
         * @return the default value is <code>false</code>
         * @see EnableDubboConfig#multiple()
         */
        @AliasFor(annotation = EnableDubboConfig.class, attribute = "multiple")
        boolean multipleConfig() default true;
    
    }
    
    • 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
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42

    核心是@EnableDubboConfig注解和@DubboComponentScan。先看@EnableDubboConfig注解源码:

    @Target({ElementType.TYPE})
    @Retention(RetentionPolicy.RUNTIME)
    @Inherited
    @Documented
    @Import(DubboConfigConfigurationRegistrar.class)
    public @interface EnableDubboConfig {
    
        /**
         * It indicates whether binding to multiple Spring Beans.
         * <p>
         * Please note that if {@link #multiple()} is <code>true</code> since 2.6.6, the multiple bean bindings will be
         * enabled, works with single bean bindings, rather than they are mutually exclusive before.
         *
         * @return the default value is <code>true</code> since 2.6.6, the value is inverse earlier.
         * @revised 2.5.9
         */
        boolean multiple() default true;
    
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    找到了熟悉的@Import注解,那么就看Import进来的这个类:

    public class DubboConfigConfigurationRegistrar implements ImportBeanDefinitionRegistrar {
    
        @Override
        public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
    
            AnnotationAttributes attributes = AnnotationAttributes.fromMap(
                    importingClassMetadata.getAnnotationAttributes(EnableDubboConfig.class.getName()));
    
            boolean multiple = attributes.getBoolean("multiple");
    
            // Single Config Bindings
            registerBeans(registry, DubboConfigConfiguration.Single.class);
    
            if (multiple) { // Since 2.6.6 https://github.com/apache/incubator-dubbo/issues/3193
                registerBeans(registry, DubboConfigConfiguration.Multiple.class);
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    可以看出,是一个BeanDefinitionRegistrar,是可以将bean注册到spring容器的,那么它将什么注册进了spring容器呢?核心代码如下:

    registerBeans(registry, DubboConfigConfiguration.Single.class);
    
    • 1

    看DubboConfigConfiguration源码:

    public class DubboConfigConfiguration {
    
        /**
         * Single Dubbo {@link AbstractConfig Config} Bean Binding
         */
        @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)
        })
        public static class Single {
    
        }
    
        /**
         * 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)
        })
        public static class Multiple {
    
        }
    }
    
    • 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

    可以看出,这里是将xml里的一些配置信息,绑定到了类里,加入到了Spring缓存。

    下面再看另一个核心注解@DubboComponentScan源码:

    @Target(ElementType.TYPE)
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    @Import(DubboComponentScanRegistrar.class)
    public @interface DubboComponentScan {
    
        /**
         * Alias for the {@link #basePackages()} attribute. Allows for more concise annotation
         * declarations e.g.: {@code @DubboComponentScan("org.my.pkg")} instead of
         * {@code @DubboComponentScan(basePackages="org.my.pkg")}.
         *
         * @return the base packages to scan
         */
        String[] value() default {};
    
        /**
         * Base packages to scan for annotated @Service classes. {@link #value()} is an
         * alias for (and mutually exclusive with) this attribute.
         * <p>
         * Use {@link #basePackageClasses()} for a type-safe alternative to String-based
         * package names.
         *
         * @return the base packages to scan
         */
        String[] basePackages() default {};
    
        /**
         * Type-safe alternative to {@link #basePackages()} for specifying the packages to
         * scan for annotated @Service classes. The package of each class specified will be
         * scanned.
         *
         * @return classes from the base packages to scan
         */
        Class<?>[] basePackageClasses() default {};
    
    }
    
    • 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
    • 36

    可以看到@Import进来了DubboComponentScanRegistrar类,看其源码:

    public class DubboComponentScanRegistrar implements ImportBeanDefinitionRegistrar {
    
        @Override
        public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
    
            Set<String> packagesToScan = getPackagesToScan(importingClassMetadata);
    
            registerServiceAnnotationBeanPostProcessor(packagesToScan, registry);
    
            registerReferenceAnnotationBeanPostProcessor(registry);
    
        }
    
        /**
         * Registers {@link ServiceAnnotationBeanPostProcessor}
         *
         * @param packagesToScan packages to scan without resolving placeholders
         * @param registry       {@link BeanDefinitionRegistry}
         * @since 2.5.8
         */
        private void registerServiceAnnotationBeanPostProcessor(Set<String> packagesToScan, BeanDefinitionRegistry registry) {
    
            BeanDefinitionBuilder builder = rootBeanDefinition(ServiceAnnotationBeanPostProcessor.class);
            builder.addConstructorArgValue(packagesToScan);
            builder.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
            AbstractBeanDefinition beanDefinition = builder.getBeanDefinition();
            BeanDefinitionReaderUtils.registerWithGeneratedName(beanDefinition, registry);
    
        }
    
        /**
         * Registers {@link ReferenceAnnotationBeanPostProcessor} into {@link BeanFactory}
         *
         * @param registry {@link BeanDefinitionRegistry}
         */
        private void registerReferenceAnnotationBeanPostProcessor(BeanDefinitionRegistry registry) {
    
            // Register @Reference Annotation Bean Processor
            BeanRegistrar.registerInfrastructureBean(registry,
                    ReferenceAnnotationBeanPostProcessor.BEAN_NAME, ReferenceAnnotationBeanPostProcessor.class);
    
        }
    
        private Set<String> getPackagesToScan(AnnotationMetadata metadata) {
            AnnotationAttributes attributes = AnnotationAttributes.fromMap(
                    metadata.getAnnotationAttributes(DubboComponentScan.class.getName()));
            String[] basePackages = attributes.getStringArray("basePackages");
            Class<?>[] basePackageClasses = attributes.getClassArray("basePackageClasses");
            String[] value = attributes.getStringArray("value");
            // Appends value array attributes
            Set<String> packagesToScan = new LinkedHashSet<String>(Arrays.asList(value));
            packagesToScan.addAll(Arrays.asList(basePackages));
            for (Class<?> basePackageClass : basePackageClasses) {
                packagesToScan.add(ClassUtils.getPackageName(basePackageClass));
            }
            if (packagesToScan.isEmpty()) {
                return Collections.singleton(ClassUtils.getPackageName(metadata.getClassName()));
            }
            return packagesToScan;
        }
    
    }
    
    
    • 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
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63

    可以看到里面有registerServiceAnnotationBeanPostProcessor方法和registerReferenceAnnotationBeanPostProcessor方法。这里注册进来两个BeanPostProcessor,一个用于扫描@Service注解,一个用于扫描@Reference注解。

    总结

    @EnableDubbo做了两件事,一个是初始化Dubbo核心组件,加载Dubbo配置到内存。另一个是注册BeanPostProcessor,用来扫描@Service和@Reference注解。

  • 相关阅读:
    敏捷开发笔记(第8章节)--单一职责原则(SRP)
    ubuntu18.04安装mysql5.7并配置数据存储路径
    java体育馆使用预约平台的设计与实现(springboot+mysql源码+文档)
    2022G3锅炉水处理考试练习题模拟考试平台操作
    c++-继承详解
    大家都能看得懂的源码之ahooks useInfiniteScroll
    从替代走向引领,永洪科技迈向全球化
    深入探讨梯度下降:优化机器学习的关键步骤(二)
    谷歌向全体员工发放万元红包:外包员工和实习生也不例外
    Java数据结构之哈希表
  • 原文地址:https://blog.csdn.net/qq1309664161/article/details/125632603