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 {
......
}
可以看到相当于是使用了EnableDubboConfig
和DubboComponentScan
这两个注解。
:
@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
中,然后会通过ReferenceBeanManager
对ReferenceBean
进行初始化:
public void prepareReferenceBeans() throws Exception {
initialized = true;
for (ReferenceBean referenceBean : getReferences()) {
initReferenceBean(referenceBean);
}
}
这样就能够获取到我们注入的配置。
以上是关于Dubbo中基于Springboot的配置注入实现的主要内容,如果未能解决你的问题,请参考以下文章
springboot-16-springboot中引入xml文件