zoukankan      html  css  js  c++  java
  • Dubbo之Config层源码解析

    通过上一遍文章整体架构中已经详细了描述了Dubbo框架的整体设计结构和调用流程,接下来,我还是深入源码,详细分析各个层的实现原理,这一篇主要讲述Config层。

    由整体的设计可以知道,Config层抽象了外部配置,各个模块的配置都会在Config层来体现。先看一下它的核心实现为org.apache.dubbo.config.AbstractConfig和org.apache.dubbo.config.ArgumentConfig。

    AbstractConfig结构图如下:

     从上图可以看到,核心的模块配置都会继承AbstractConfig 。但是既然是配置,那么怎么读取这些配置呢?

    Dubbo基于Java注解的配置原理
    @EnableDubbo是Dubbo使用注解初始化的核心注解,先看一下源码:

    /**
     * Enables Dubbo components as Spring Beans, equals
     * {@link DubboComponentScan} and {@link EnableDubboConfig} combination.
     * <p>
     * Note : {@link EnableDubbo} must base on Spring Framework 4.2 and above
     *
     * @author zhaodongchao
     * @see DubboComponentScan
     * @see EnableDubboConfig
     * @since 2.5.8
     */
    @Target({ElementType.TYPE})
    @Retention(RetentionPolicy.RUNTIME)
    @Inherited
    @Documented
    @EnableDubboConfig
    @DubboComponentScan
    @EnableDubboLifecycle
    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;
    
    }

    本身只是定义了几个配置属性,没有具体的实现逻辑。而它上面有标记了三个注解,如下图:

     

     再在@EnableDubbo注解上的上个额外的注解:

    @EnableDubboConfig
    从配置文件中解析配置文件,并实例化相关的config对象到spring 容器中

    @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.class)**

    这里摘录:https://blog.csdn.net/boling_cavalry/article/details/82530167这篇文章中对@Import用法的说明:
    在@Import注解的参数中可以填写类名,例如@Import(Abc.class),根据类Abc的不同类型,spring容器有以下四种处理方式:

    如果Abc类实现了ImportSelector接口,spring容器就会实例化Abc类,并且调用其selectImports方法;
    DeferredImportSelector是ImportSelector的子类,如果Abc类实现了DeferredImportSelector接口,spring容器就会实例化Abc类,并且调用其selectImports方法,和ImportSelector的实例不同的是,DeferredImportSelector的实例的selectImports方法调用时机晚于ImportSelector的实例,要等到@Configuration注解中相关的业务全部都处理完了才会调用(具体逻辑在ConfigurationClassParser.processDeferredImportSelectors方法中),想了解更多DeferredImportSelector和ImportSelector的区别,请参考《ImportSelector与DeferredImportSelector的区别(spring4) 》;
    如果Abc类实现了ImportBeanDefinitionRegistrar接口,spring容器就会实例化Abc类,并且调用其registerBeanDefinitions方法;
    如果Abc没有实现ImportSelector、DeferredImportSelector、ImportBeanDefinitionRegistrar等其中的任何一个,spring容器就会实例化Abc类;
    现在再看一下DubboConfigConfigurationRegistrar是属于上面说的四种情况的哪一种?

    /**
     * Dubbo {@link AbstractConfig Config} {@link ImportBeanDefinitionRegistrar register}, which order can be configured
     *
     * @see EnableDubboConfig
     * @see DubboConfigConfiguration
     * @see Ordered
     * @since 2.5.8
     */
    public class DubboConfigConfigurationRegistrar implements ImportBeanDefinitionRegistrar {
    
        @Override
        public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
            //获取配置类中@EnableDubboConfig这个注解对象
            AnnotationAttributes attributes = AnnotationAttributes.fromMap(
                    importingClassMetadata.getAnnotationAttributes(EnableDubboConfig.class.getName()));
             
            boolean multiple = attributes.getBoolean("multiple");
    
            // Single Config Bindings
            registerBeans(registry, DubboConfigConfiguration.Single.class);
            /*是否一个配置的多个属性值,如:
            # Single configuration binding
            dubbo.protocol.name=dubbo
            # Multiple configuration binding
            dubbo.protcols.rest.name = rest
             */
            if (multiple) { // Since 2.6.6 https://github.com/apache/dubbo/issues/3193
                registerBeans(registry, DubboConfigConfiguration.Multiple.class);
            }
    
            // Register DubboConfigAliasPostProcessor
            registerDubboConfigAliasPostProcessor(registry);
    
            // Register NamePropertyDefaultValueDubboConfigBeanCustomizer
            registerDubboConfigBeanCustomizers(registry);
    
        }
    
        private void registerDubboConfigBeanCustomizers(BeanDefinitionRegistry registry) {
            registerInfrastructureBean(registry, BEAN_NAME, NamePropertyDefaultValueDubboConfigBeanCustomizer.class);
        }
    
        /**
         * Register {@link DubboConfigAliasPostProcessor}
         *
         * @param registry {@link BeanDefinitionRegistry}
         * @since 2.7.4 [Feature] https://github.com/apache/dubbo/issues/5093
         */
        private void registerDubboConfigAliasPostProcessor(BeanDefinitionRegistry registry) {
            registerInfrastructureBean(registry, DubboConfigAliasPostProcessor.BEAN_NAME, DubboConfigAliasPostProcessor.class);
        }
    
    }

    很明显是属于第三种,实现了ImportBeanDefinitionRegistrar接口。因此在程序启动时会实例化DubboConfigConfigurationRegistrar并调用registerBeanDefinitions方法。

    这里面有一个核心的对象:DubboConfigConfiguration 。它定义注册那些配置类到spring容器中的核心配置类。
    看源码:

    /**
     * Dubbo {@link AbstractConfig Config} {@link Configuration}
     *
     * @revised 2.7.5
     * @see Configuration
     * @see EnableConfigurationBeanBindings
     * @see EnableConfigurationBeanBinding
     * @see ApplicationConfig
     * @see ModuleConfig
     * @see RegistryConfig
     * @see ProtocolConfig
     * @see MonitorConfig
     * @see ProviderConfig
     * @see ConsumerConfig
     * @see org.apache.dubbo.config.ConfigCenterConfig
     * @since 2.5.8
     */
    public class DubboConfigConfiguration {
    
        /**
         * Single Dubbo {@link AbstractConfig Config} Bean Binding
         */
        @EnableConfigurationBeanBindings({
                @EnableConfigurationBeanBinding(prefix = "dubbo.application", type = ApplicationConfig.class),
                @EnableConfigurationBeanBinding(prefix = "dubbo.module", type = ModuleConfig.class),
                @EnableConfigurationBeanBinding(prefix = "dubbo.registry", type = RegistryConfig.class),
                @EnableConfigurationBeanBinding(prefix = "dubbo.protocol", type = ProtocolConfig.class),
                @EnableConfigurationBeanBinding(prefix = "dubbo.monitor", type = MonitorConfig.class),
                @EnableConfigurationBeanBinding(prefix = "dubbo.provider", type = ProviderConfig.class),
                @EnableConfigurationBeanBinding(prefix = "dubbo.consumer", type = ConsumerConfig.class),
                @EnableConfigurationBeanBinding(prefix = "dubbo.config-center", type = ConfigCenterBean.class),
                @EnableConfigurationBeanBinding(prefix = "dubbo.metadata-report", type = MetadataReportConfig.class),
                @EnableConfigurationBeanBinding(prefix = "dubbo.metrics", type = MetricsConfig.class)
        })
        public static class Single {
    
        }
    
        /**
         * Multiple Dubbo {@link AbstractConfig Config} Bean Binding
         */
        @EnableConfigurationBeanBindings({
                @EnableConfigurationBeanBinding(prefix = "dubbo.applications", type = ApplicationConfig.class, multiple = true),
                @EnableConfigurationBeanBinding(prefix = "dubbo.modules", type = ModuleConfig.class, multiple = true),
                @EnableConfigurationBeanBinding(prefix = "dubbo.registries", type = RegistryConfig.class, multiple = true),
                @EnableConfigurationBeanBinding(prefix = "dubbo.protocols", type = ProtocolConfig.class, multiple = true),
                @EnableConfigurationBeanBinding(prefix = "dubbo.monitors", type = MonitorConfig.class, multiple = true),
                @EnableConfigurationBeanBinding(prefix = "dubbo.providers", type = ProviderConfig.class, multiple = true),
                @EnableConfigurationBeanBinding(prefix = "dubbo.consumers", type = ConsumerConfig.class, multiple = true),
                @EnableConfigurationBeanBinding(prefix = "dubbo.config-centers", type = ConfigCenterBean.class, multiple = true),
                @EnableConfigurationBeanBinding(prefix = "dubbo.metadata-reports", type = MetadataReportConfig.class, multiple = true),
                @EnableConfigurationBeanBinding(prefix = "dubbo.metricses", type = MetricsConfig.class, multiple = true)
        })
        public static class Multiple {
    
        }
    }

    从源码可以知道,@EnableDubboConfig 的作用就是解析配置文件中前缀为:

    dubbo.application / dubbo.applications的配置属性 到ApplicationConfig对象实例中,并注册到spring 容器中
    dubbo.module / dubbo.modules的配置属性到ModuleConfig对象实例中,并注册到spring 容器中
    dubbo.registrie / dubbo.registries的配置属性到RegistryConfig对象实例中,并注册到spring 容器中
    dubbo.protocol / dubbo.protocols的配置属性到ProtocolConfig对象实例中,并注册到spring 容器中
    dubbo.monitor / dubbo.monitors的配置属性到MonitorConfig对象实例中,并注册到spring 容器中
    dubbo.provider / dubbo.providers的配置属性到ProviderConfig对象实例中,并注册到spring 容器中
    dubbo.consumer / dubbo.consumers的配置属性到ConsumerConfig对象实例中,并注册到spring 容器中
    dubbo.config-center / dubbo.config-centers的配置属性到ConfigCenterBean对象实例中,并注册到spring 容器中
    dubbo.metadata-report / dubbo.metadata-reports的配置属性到MetadataReportConfig对象实例中,并注册到spring 容器中
    dubbo.metricse / dubbo.metricses的配置属性到MetricsConfig对象实例中,并注册到spring 容器中

    这是重点哦

    @DubboComponentScan dubbo组件扫描
    扫描使用注解 @Service和@Reference注解标注的类和属性,自动注册到spring 容器中 。
    源码:

    /**
     * Dubbo Component Scan {@link Annotation},scans the classpath for annotated components that will be auto-registered as
     * Spring beans. Dubbo-provided {@link Service} and {@link Reference}.
     *
     * @see Service
     * @see Reference
     * @since 2.5.7
     */
    @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 {};
    
    }

    这里又用到了@Import ,那就再看一下DubboComponentScanRegistrar源码:

    /**
     * Dubbo {@link DubboComponentScan} Bean Registrar
     *
     * @see Service
     * @see DubboComponentScan
     * @see ImportBeanDefinitionRegistrar
     * @see ServiceAnnotationBeanPostProcessor
     * @see ReferenceAnnotationBeanPostProcessor
     * @since 2.5.7
     */
    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
            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;
        }
    
    }

    可以看到,目标很明确,就是处理@Service和@Reference注解,并实例化相关对象。

    @EnableDubboLifecycle Dubbo生命周期管理

    /**
     * Enables Dubbo {@link Lifecycle} components
     *
     * @since 2.7.5
     */
    @Target({ElementType.TYPE})
    @Retention(RetentionPolicy.RUNTIME)
    @Inherited
    @Documented
    @Import(DubboLifecycleComponentRegistrar.class)
    public @interface EnableDubboLifecycle {
    }

    再看DubboLifecycleComponentRegistrar

    /**
     * A {@link ImportBeanDefinitionRegistrar register} for the {@link Lifecycle Dubbo Lifecycle} components
     *
     * @since 2.7.5
     */
    public class DubboLifecycleComponentRegistrar implements ImportBeanDefinitionRegistrar {
    
        @Override
        public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
            //注册dubbo组件生命周期监听器到spring容器中,DubboLifecycleComponentApplicationListener是一个ApplicationListener对象
            registerBeans(registry, DubboLifecycleComponentApplicationListener.class);
        }
    }

    再看DubboLifecycleComponentApplicationListener :

    /**
     * A {@link ApplicationListener listener} for the {@link Lifecycle Dubbo Lifecycle} components
     *
     * @see {@link Lifecycle Dubbo Lifecycle}
     * @see SmartApplicationListener
     * @since 2.7.5
     */
    public class DubboLifecycleComponentApplicationListener implements ApplicationListener {
    
        @Override
        public void onApplicationEvent(ApplicationEvent event) {
    
            if (!supportsEvent(event)) {
                return;
            }
    
            if (event instanceof ContextRefreshedEvent) {
                onContextRefreshedEvent((ContextRefreshedEvent) event);
            } else if (event instanceof ContextClosedEvent) {
                onContextClosedEvent((ContextClosedEvent) event);
            }
        }
    
        protected void onContextRefreshedEvent(ContextRefreshedEvent event) {
            ApplicationContext context = event.getApplicationContext();
            DubboBootstrap bootstrap = loadBootsttrapAsBean(context);
            if (bootstrap == null) {
                bootstrap = DubboBootstrap.getInstance();
            }
            bootstrap.start();
        }
    
        protected void onContextClosedEvent(ContextClosedEvent event) {
            DubboShutdownHook.getDubboShutdownHook().doDestroy();
        }
    
        private DubboBootstrap loadBootsttrapAsBean(ApplicationContext context) {
            Map<String, DubboBootstrap> beans = beansOfTypeIncludingAncestors(context, DubboBootstrap.class);
            if (CollectionUtils.isNotEmptyMap(beans)) {
                return beans.values().iterator().next();
            }
            return null;
        }
    
        /**
         * the specified {@link ApplicationEvent event} must be {@link ApplicationContextEvent} and
         * its correlative {@link ApplicationContext} must be root
         *
         * @param event
         * @return
         */
        private boolean supportsEvent(ApplicationEvent event) {
            return event instanceof ApplicationContextEvent &&
                    isRootApplicationContext((ApplicationContextEvent) event);
        }
    
    
        private boolean isRootApplicationContext(ApplicationContextEvent event) {
            return event.getApplicationContext().getParent() == null;
        }
    }

    可以看到,在生命周期监听器里面维护了两个重要的对象DubboBootstrap和DubboShutdownHook

    DubboBootstrap Dubbo启动引导器
    被设计单例模式,dubbo程序全局中值存在一个实例。在监听到spring 容器的ContextRefreshedEvent事件时,会获取其实例,并调用start()方法
    DubboShutdownHook Dubbo程序关闭钩子,
    在监听到spring 容器的关闭事件之后会掉DubboShutdownHook#doDestroy()方法,关闭dubbo容器。
    ————————————————
    版权声明:本文为CSDN博主「峡谷程序猿」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
    原文链接:https://blog.csdn.net/zhaodongchao1992/article/details/103452829

  • 相关阅读:
    ubuntu切换到root
    ubuntu vim退出时出错
    easy_install和pip的安装及使用
    Swap file "/etc/.hosts.swp" already exists! [O]pen Read-Only, (E)dit anyway, (R)ecover, (D)elete it,
    ERROR 2003 (HY000): Can't connect to MySQL server on 'ip地址' (110)
    Android-PullToRefresh(一)
    Android Exception 6 (adapter is not modified from a background thread)
    Android Exception 5(startActivityForResult & singleTask)
    【协议篇】UDP
    【协议篇】TCP
  • 原文地址:https://www.cnblogs.com/nizuimeiabc1/p/14855802.html
Copyright © 2011-2022 走看看