Dubbo中基于Springboot的配置注入实现

Posted Leo Han

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Dubbo中基于Springboot的配置注入实现相关的知识,希望对你有一定的参考价值。

我们知道,当我们使用springboot框架引入Dubbo的时候,只需要在启动类上加入EnableDubbo注解的时候就能够注入Dubbo相关配置,我们看下怎么实现。
如果要了解这篇文档的一些内容,需要先看下之前对Springboot配置的研究SpringBoot源码读取配置源码分析,配置优先级,加载Bean信息
当我们在引入dubbo-spring-boot-starter模块的时候,查看包下面对应的spring.factorues文件,会自动注入如下类:

org.springframework.boot.autoconfigure.EnableAutoConfiguration=\\
org.apache.dubbo.spring.boot.autoconfigure.DubboAutoConfiguration,\\
org.apache.dubbo.spring.boot.autoconfigure.DubboRelaxedBindingAutoConfiguration
org.springframework.context.ApplicationListener=\\
org.apache.dubbo.spring.boot.context.event.DubboConfigBeanDefinitionConflictApplicationListener,\\
org.apache.dubbo.spring.boot.context.event.WelcomeLogoApplicationListener,\\
org.apache.dubbo.spring.boot.context.event.AwaitingNonWebApplicationListener
org.springframework.boot.env.EnvironmentPostProcessor=\\
org.apache.dubbo.spring.boot.env.DubboDefaultPropertiesEnvironmentPostProcessor
org.springframework.context.ApplicationContextInitializer=\\
org.apache.dubbo.spring.boot.context.DubboApplicationContextInitializer

而这里的DubboAutoConfiguration就是实现注入的关键:

@ConditionalOnProperty(prefix = DUBBO_PREFIX, name = "enabled", matchIfMissing = true)
@Configuration
@AutoConfigureAfter(DubboRelaxedBindingAutoConfiguration.class)
@EnableConfigurationProperties(DubboConfigurationProperties.class)
@EnableDubboConfig
public class DubboAutoConfiguration implements ApplicationContextAware, BeanDefinitionRegistryPostProcessor {
	.......
}

而这里的DubboConfigurationProperties

@ConfigurationProperties(DUBBO_PREFIX)
public class DubboConfigurationProperties {

    @NestedConfigurationProperty
    private Config config = new Config();

    @NestedConfigurationProperty
    private Scan scan = new Scan();

    // Single Config Bindings
    @NestedConfigurationProperty
    private ApplicationConfig application = new ApplicationConfig();

    @NestedConfigurationProperty
    private ModuleConfig module = new ModuleConfig();

    @NestedConfigurationProperty
    private RegistryConfig registry = new RegistryConfig();

    @NestedConfigurationProperty
    private ProtocolConfig protocol = new ProtocolConfig();

    @NestedConfigurationProperty
    private MonitorConfig monitor = new MonitorConfig();

    @NestedConfigurationProperty
    private ProviderConfig provider = new ProviderConfig();

    @NestedConfigurationProperty
    private ConsumerConfig consumer = new ConsumerConfig();

    @NestedConfigurationProperty
    private ConfigCenterBean configCenter = new ConfigCenterBean();

    @NestedConfigurationProperty
    private MetadataReportConfig metadataReport = new MetadataReportConfig();

    // Multiple Config Bindings

    private Map<String, ModuleConfig> modules = new LinkedHashMap<>();

    private Map<String, RegistryConfig> registries = new LinkedHashMap<>();

    private Map<String, ProtocolConfig> protocols = new LinkedHashMap<>();

    private Map<String, MonitorConfig> monitors = new LinkedHashMap<>();

    private Map<String, ProviderConfig> providers = new LinkedHashMap<>();

    private Map<String, ConsumerConfig> consumers = new LinkedHashMap<>();

    private Map<String, ConfigCenterBean> configCenters = new LinkedHashMap<>();

    private Map<String, MetadataReportConfig> metadataReports = new LinkedHashMap<>();

这里就是对应了我们经常在spring的配置文件中配置的形如:

dubbo.registry.xxxx=aaa
dubbo.protocol.xxxx=bbb

当我们使用EnableDubbo注解的时候,其结构如下:

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
@EnableDubboConfig
@DubboComponentScan
public @interface EnableDubbo {
......
}

可以看到相当于是使用了EnableDubboConfigDubboComponentScan这两个注解。

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

这里如果使用EnableDubboConfig注解会向spring容器注入DubboConfigConfigurationRegistrar

public class DubboConfigConfigurationRegistrar implements ImportBeanDefinitionRegistrar {

    @Override
    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
        registerCommonBeans(registry);
    }
}
static void registerCommonBeans(BeanDefinitionRegistry registry) {

        registerInfrastructureBean(registry, ServicePackagesHolder.BEAN_NAME, ServicePackagesHolder.class);

        registerInfrastructureBean(registry, ReferenceBeanManager.BEAN_NAME, ReferenceBeanManager.class);

        // Since 2.5.7 Register @Reference Annotation Bean Processor as an infrastructure Bean
        registerInfrastructureBean(registry, ReferenceAnnotationBeanPostProcessor.BEAN_NAME,
                ReferenceAnnotationBeanPostProcessor.class);

        // TODO Whether DubboConfigAliasPostProcessor can be removed ?
        // Since 2.7.4 [Feature] https://github.com/apache/dubbo/issues/5093
        registerInfrastructureBean(registry, DubboConfigAliasPostProcessor.BEAN_NAME,
                DubboConfigAliasPostProcessor.class);

        // Since 2.7.4 Register DubboBootstrapApplicationListener as an infrastructure Bean
        registerInfrastructureBean(registry, DubboBootstrapApplicationListener.BEAN_NAME,
                DubboBootstrapApplicationListener.class);

        // Since 2.7.6 Register DubboConfigDefaultPropertyValueBeanPostProcessor as an infrastructure Bean
        registerInfrastructureBean(registry, DubboConfigDefaultPropertyValueBeanPostProcessor.BEAN_NAME,
                DubboConfigDefaultPropertyValueBeanPostProcessor.class);

        // Dubbo config initializer
        registerInfrastructureBean(registry, DubboConfigBeanInitializer.BEAN_NAME, DubboConfigBeanInitializer.class);

        // register infra bean if not exists later
        registerInfrastructureBean(registry, DubboInfraBeanRegisterPostProcessor.BEAN_NAME, DubboInfraBeanRegisterPostProcessor.class);
    }

可以看到,这里会向spring容器注入如下bean:

  • ServicePackagesHolder
  • ReferenceBeanManager:管理ReferenceBean
  • ReferenceAnnotationBeanPostProcessor: 主要用来处理DubboReference注解
  • DubboConfigAliasPostProcessor
  • DubboBootstrapApplicationListener
  • DubboConfigDefaultPropertyValueBeanPostProcessor
  • DubboConfigBeanInitializer
  • DubboInfraBeanRegisterPostProcessor

我们通过DubboAutoConfiguration将配置文件中的配置映射到对应配置类中,而这里注入的各种类,则会利用注入的配置类将相关Server、Reference进行初始化。
比如DubboBootstrapApplicationListener:

public void onApplicationEvent(ApplicationEvent event) {
        if (isOriginalEventSource(event)) {
            if (event instanceof DubboAnnotationInitedEvent) {
                // This event will be notified at AbstractApplicationContext.registerListeners(),
                // init dubbo config beans before spring singleton beans
                applicationContext.getBean(DubboConfigBeanInitializer.BEAN_NAME, DubboConfigBeanInitializer.class);

                // All infrastructure config beans are loaded, initialize dubbo here
                DubboBootstrap.getInstance().initialize();
            } else if (event instanceof ApplicationContextEvent) {
                this.onApplicationContextEvent((ApplicationContextEvent) event);
            }
        }
    }

DubboBootstrapApplicationListener在收到DubboAnnotationInitedEvent事件后,会调用DubboBootstrap进行初始化:

public synchronized void initialize() {
        if (!initialized.compareAndSet(false, true)) {
            return;
        }
        ApplicationModel.initFrameworkExts();
        startConfigCenter();
        loadConfigsFromProps();
        checkGlobalConfigs();
        startMetadataCenter();
        initMetadataService();
    }

DubboBootstrap主要是用来启动Dubbo的,为了屏蔽各种依赖框架而单独提取出来的一个启动辅助类。
这里有很多动作,包括对配置的各种检查等。
DubboConfigBeanInitializer:

public void afterPropertiesSet() throws Exception {
        init();
    }

    private void init() {
        if (initialized.compareAndSet(false, true)) {
            configManager = ApplicationModel.getConfigManager();
            referenceBeanManager = beanFactory.getBean(ReferenceBeanManager.BEAN_NAME, ReferenceBeanManager.class);
            try {
                prepareDubboConfigBeans();
                referenceBeanManager.prepareReferenceBeans();
            } catch (Throwable e) {
                throw new FatalBeanException("Initialization dubbo config beans failed", e);
            }
        }
    }

    /**
     * Initializes there Dubbo's Config Beans before @Reference bean autowiring
     */
    private void prepareDubboConfigBeans() {
        //Make sure all these config beans are inited and registered to ConfigManager
        loadConfigBeansOfType(ApplicationConfig.class);
        loadConfigBeansOfType(ModuleConfig.class);
        loadConfigBeansOfType(RegistryConfig.class);
        loadConfigBeansOfType(ProtocolConfig.class);
        loadConfigBeansOfType(MonitorConfig.class);
        loadConfigBeansOfType(ProviderConfig.class);
        loadConfigBeansOfType(ConsumerConfig.class);
        loadConfigBeansOfType(ConfigCenterBean.class);
        loadConfigBeansOfType(MetadataReportConfig.class);
        loadConfigBeansOfType(MetricsConfig.class);
        loadConfigBeansOfType(SslConfig.class);
    }

    private void loadConfigBeansOfType(Class<? extends AbstractConfig> configClass) {
        String[] beanNames = beanFactory.getBeanNamesForType(configClass, true, false);
        for (String beanName : beanNames) {
            AbstractConfig configBean = beanFactory.getBean(beanName, configClass);
            configManager.addConfig(configBean);
        }
    }

DubboConfigBeanInitializer将各种配置都注入到了ConfigManager中,然后会通过ReferenceBeanManagerReferenceBean进行初始化:

public void prepareReferenceBeans() throws Exception {
        initialized = true;
        for (ReferenceBean referenceBean : getReferences()) {
            initReferenceBean(referenceBean);
        }
}

这样就能够获取到我们注入的配置。

以上是关于Dubbo中基于Springboot的配置注入实现的主要内容,如果未能解决你的问题,请参考以下文章

Dubbo整合SpringBoot

Dubbo整合SpringBoot

springboot-16-springboot中引入xml文件

dubbo整合springboot

dubbo学习 springboot整合dubbo mybatis mysql

dubbo+zookeeper下生产者和消费者配置(基于springboot开发)