精品源碼
Eureka精品源碼java
Quartz系列全集
spring
xxl-job系列springboot
版本說明
springboot starter : 0.1.1ide
dubbo版本: 2.6.2post
自動配置類
@Configuration
@ConditionalOnProperty(prefix = DUBBO_PREFIX, name = "enabled", matchIfMissing = true, havingValue = "true")
@ConditionalOnClass(AbstractConfig.class)
public class DubboAutoConfiguration {
// 單個dubbo配置綁定bean , 默認就是單個
@EnableDubboConfig
protected static class SingleDubboConfigConfiguration {
}
/**
* 多個dubbo配置綁定bean , 默認不使用。
*
*/
@ConditionalOnProperty(name = MULTIPLE_CONFIG_PROPERTY_NAME, havingValue = "true")
@EnableDubboConfig(multiple = true)
protected static class MultipleDubboConfigConfiguration {
}
/**
* service類,服務提供者的BeanDefinitionRegistryPostProcessor類,用來解析
* @Service註解,生成Service的BeanDefinition類,放入spring容器,供spring容器生成Bean
*
*/
@ConditionalOnProperty(name = BASE_PACKAGES_PROPERTY_NAME)
@ConditionalOnClass(RelaxedPropertyResolver.class)
@Bean
public ServiceAnnotationBeanPostProcessor serviceAnnotationBeanPostProcessor(Environment environment) {
RelaxedPropertyResolver resolver = new RelaxedPropertyResolver(environment);
Set<String> packagesToScan = resolver.getProperty(BASE_PACKAGES_PROPERTY_NAME, Set.class, emptySet());
return new ServiceAnnotationBeanPostProcessor(packagesToScan);
}
// springboot dataBinder 機制的擴展,用來將具體的屬性設置到相應的實體類裏面去。
@ConditionalOnClass(RelaxedDataBinder.class)
@Bean
@Scope(scopeName = SCOPE_PROTOTYPE)
public RelaxedDubboConfigBinder relaxedDubboConfigBinder() {
return new RelaxedDubboConfigBinder();
}
/**
* 用來解析@Reference 註解,消費者引用哪些服務,經過這個註解來進行引用
* 給標註這個@Reference註解的屬性賦值, 和@autowired的作法相似。
*
*/
@ConditionalOnMissingBean
@Bean(name = ReferenceAnnotationBeanPostProcessor.BEAN_NAME)
public ReferenceAnnotationBeanPostProcessor referenceAnnotationBeanPostProcessor() {
return new ReferenceAnnotationBeanPostProcessor();
}
}
配置說明:ui
SingleDubboConfigConfiguration : 引入了單個dubbo配置綁定bean的配置 , 默認使用this
// 配置以下
dubbo.application
dubbo.module
dubbo.registry
dubbo.protocol
dubbo.monitor
dubbo.provider
dubbo.consumer
**MultipleDubboConfigConfiguration ** :多個dubbo配置綁定bean , 默認不使用。Dubbo @Service
和 @Reference
容許 Dubbo 應用關聯ApplicationConfig
Bean 或者指定多個RegistryConfig
Bean 等能力。換句話說,Dubbo 應用上下文中可能存在多個ApplicationConfig
等 Bean定義。url
// 配置以下
dubbo.applications
dubbo.modules
dubbo.registries
dubbo.protocols
dubbo.monitors
dubbo.providers
dubbo.consumers
**serviceAnnotationBeanPostProcessor ** :解析service類註解的類,若是在spring boot啓動類上配置了@DubboComponentScan
則默認不使用。
**referenceAnnotationBeanPostProcessor ** : 爲@Reference
注入對象,若是在spring boot啓動類上配置了@DubboComponentScan
則默認不使用。
由於在@DubboComponentScan
這個註解中引入了DubboComponentScanRegistrar
這個註冊類,該類中作了解析@service
註解和@Reference
的事情
@EnableDubboConfig
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
@Import(DubboConfigConfigurationSelector.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 false;
}
主要的做用就是導入了這個類DubboConfigConfigurationSelector
DubboConfigConfigurationSelector
public class DubboConfigConfigurationSelector implements ImportSelector, Ordered {
@Override
public String[] selectImports(AnnotationMetadata importingClassMetadata) {
// 獲取註解上的屬性,這個是經過@EnableDubboConfig導入的,因此AnnotationMetadata裏面就包含了這個註解的值
AnnotationAttributes attributes = AnnotationAttributes.fromMap(
importingClassMetadata.getAnnotationAttributes(EnableDubboConfig.class.getName()));
// 是不是多配置,默認爲false
boolean multiple = attributes.getBoolean("multiple");
if (multiple) {
return of(DubboConfigConfiguration.Multiple.class.getName());
} else {
// 這裏就直接講解單配置的。
return of(DubboConfigConfiguration.Single.class.getName());
}
}
private static <T> T[] of(T... values) {
return values;
}
@Override
public int getOrder() {
return HIGHEST_PRECEDENCE;
}
}
DubboConfigConfigurationSelector
這個類實現了ImportSelector
接口,該接口的selectImports方法就是返回bean的名稱,供spring初始化,因此這裏返回了
DubboConfigConfiguration.Single.class.getName() , spring就會初始化這個類了。
Single
DubboConfigConfiguration.Single
的代碼以下 , 經過@EnableDubboConfigBindings註解,導入了多個@EnableDubboConfigBinding
@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 {
}
EnableDubboConfigBindings
由上面能夠看到,spring在初始化Single這個類的時候,必然會加載他上面的註解,該類的主要做用就是爲了導入它上面的註解,@EnableDubboConfigBindings
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(DubboConfigBindingsRegistrar.class) // 導入了這個類。
public @interface EnableDubboConfigBindings {
/**
* The value of {@link EnableDubboConfigBindings}
*
* @return non-null
*/
EnableDubboConfigBinding[] value();
}
@EnableDubboConfigBindings
註解導入了DubboConfigBindingsRegistrar這個類,該類的做用是將配置屬性和dubbo的配置進行綁定。註解的value是7個子註解
@EnableDubboConfigBinding
,後面DubboConfigBindingsRegistrar解析的時候,會獲取到這個7個子註解,將對應的屬性和dubbo的配置類進行綁定。
DubboConfigBindingsRegistrar
public class DubboConfigBindingsRegistrar implements ImportBeanDefinitionRegistrar, EnvironmentAware {
private ConfigurableEnvironment environment;
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
// 獲取導入此類的註解信息,@EnableDubboConfigBindings
AnnotationAttributes attributes = AnnotationAttributes.fromMap(
importingClassMetadata.getAnnotationAttributes(EnableDubboConfigBindings.class.getName()));
// 獲取@EnableDubboConfigBinding 子註解
AnnotationAttributes[] annotationAttributes = attributes.getAnnotationArray("value");
// 初始化DubboConfigBindingRegistrar類,該類的主要做用就是爲了解析單個的@EnableDubboConfigBinding註解
DubboConfigBindingRegistrar registrar = new DubboConfigBindingRegistrar();
registrar.setEnvironment(environment);
for (AnnotationAttributes element : annotationAttributes) {
// 循環註冊,經過註解裏面的信息,生成Dubbo配置的BeanDefinition,最後放入spring容器中,供spring容器實例化。
registrar.registerBeanDefinitions(element, registry);
}
}
@Override
public void setEnvironment(Environment environment) {
Assert.isInstanceOf(ConfigurableEnvironment.class, environment);
this.environment = (ConfigurableEnvironment) environment;
}
}
註冊dubbo的配置bean
protected void registerBeanDefinitions(AnnotationAttributes attributes, BeanDefinitionRegistry registry) {
//1. 從環境 中取出 響應的屬性名
String prefix = environment.resolvePlaceholders(attributes.getString("prefix"));
// 2. 獲取dubbo的配置類的class
Class<? extends AbstractConfig> configClass = attributes.getClass("type");
// 3. 獲取是不是多個dubbo的配置
boolean multiple = attributes.getBoolean("multiple");
// 註冊dubbo的配置bean
registerDubboConfigBeans(prefix, configClass, multiple, registry);
}
步驟說明:
1.參數attributes就是@EnableDubboConfigBinding裏面的屬性,獲取prefix屬性值,就是獲取到了:dubbo.application
例:
@EnableDubboConfigBinding(prefix = "dubbo.application", type = ApplicationConfig.class)
2.獲取dubbo的配置類的class,也就是獲取到了ApplicationConfig.class
3.獲取multiple的值,默認沒有配置就是false
4.調用registerDubboConfigBeans方法生成dubbo的配置bean
private void registerDubboConfigBeans(String prefix,
Class<? extends AbstractConfig> configClass,
boolean multiple,
BeanDefinitionRegistry registry) {
// 根據屬性名,如:dubbo.application 獲取具體的屬性值
Map<String, String> properties = getSubProperties(environment.getPropertySources(), prefix);
if (CollectionUtils.isEmpty(properties)) {
// 若是沒有配置,則沒有必要生成對應的dubbo配置bean了
if (log.isDebugEnabled()) {
log.debug("There is no property for binding to dubbo config class [" + configClass.getName()
+ "] within prefix [" + prefix + "]");
}
return;
}
// BeanName
Set<String> beanNames = multiple ? resolveMultipleBeanNames(properties) :
Collections.singleton(resolveSingleBeanName(properties, configClass, registry));
for (String beanName : beanNames) {
// 生成bena
registerDubboConfigBean(beanName, configClass, registry);
// 註冊dubbo的DubboConfigBindingBeanPostProcessor
registerDubboConfigBindingBeanPostProcessor(prefix, beanName, multiple, registry);
}
}
private void registerDubboConfigBean(String beanName, Class<? extends AbstractConfig> configClass,
BeanDefinitionRegistry registry) {
// 生成BeanDefinitionBuilder
BeanDefinitionBuilder builder = rootBeanDefinition(configClass);
AbstractBeanDefinition beanDefinition = builder.getBeanDefinition();
// 經過BeanDefinitionRegistry註冊dubbo的配置bean
registry.registerBeanDefinition(beanName, beanDefinition);
if (log.isInfoEnabled()) {
log.info("The dubbo config bean definition [name : " + beanName + ", class : " + configClass.getName() +
"] has been registered.");
}
}
DubboConfigBindingBeanPostProcessor
這個類是在dubbo的配置類初始化完成後會執行響應的方法。用來將屬性值設置到對應的屬性裏面去,在springboot中咱們存在這種狀況
first-name
,firstName
, FIRST_NAME
, 好比咱們在yaml文件中配置這樣的屬性,咱們的java bean中的屬性是firstName , 在使用@ConfigurationProperties
註解的時候咱們無需擔憂,若是不是用springboot自身的config類來注入,那麼咱們本身處理這種狀況就會變的很是麻煩,因此dubbo選擇的是經過RelaxedDataBinder類來處理這個問題。這是spring boot的機制。
DubboConfigBindingBeanPostProcessor類實現了BeanPostProcessor
,ApplicationContextAware
, InitializingBean
這三個接口,下面是挑了一些重要的方法展現出來 , **每一個dubbo配置類都有相應的DubboConfigBindingBeanPostProcessor **
public DubboConfigBindingBeanPostProcessor(String prefix, String beanName) {
Assert.notNull(prefix, "The prefix of Configuration Properties must not be null");
Assert.notNull(beanName, "The name of bean must not be null");
this.prefix = prefix; // 屬性前綴
this.beanName = beanName; // dubbo的配置類名
}
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
// 會在每個bean實例化以後、初始化(如afterPropertiesSet方法)以前被調用。
if (beanName.equals(this.beanName) && bean instanceof AbstractConfig) {
AbstractConfig dubboConfig = (AbstractConfig) bean;
// 將屬性和配置進行綁定
dubboConfigBinder.bind(prefix, dubboConfig);
if (log.isInfoEnabled()) {
log.info("The properties of bean [name : " + beanName + "] have been binding by prefix of " +
"configuration properties : " + prefix);
}
}
return bean;
}
@Override
public void afterPropertiesSet() throws Exception {
// DubboConfigBindingBeanPostProcessor 初始化以後就會執行
if (dubboConfigBinder == null) {
try {
// 從容器中獲取DubboConfigBinder , DubboConfigBinder的做用範圍是prototype , 每次調用getbean都會新建立一個
dubboConfigBinder = applicationContext.getBean(DubboConfigBinder.class);
} catch (BeansException ignored) {
if (log.isDebugEnabled()) {
log.debug("DubboConfigBinder Bean can't be found in ApplicationContext.");
}
// Use Default implementation
dubboConfigBinder = createDubboConfigBinder(applicationContext.getEnvironment());
}
}
dubboConfigBinder.setIgnoreUnknownFields(ignoreUnknownFields);
dubboConfigBinder.setIgnoreInvalidFields(ignoreInvalidFields);
}
dubboConfigBinder的代碼以下,下面主要就是調用springboot 的dataBinder機制進行屬性設值了
public class RelaxedDubboConfigBinder extends AbstractDubboConfigBinder {
@Override
public <C extends AbstractConfig> void bind(String prefix, C dubboConfig) {
RelaxedDataBinder relaxedDataBinder = new RelaxedDataBinder(dubboConfig);
// Set ignored*
relaxedDataBinder.setIgnoreInvalidFields(isIgnoreInvalidFields());
relaxedDataBinder.setIgnoreUnknownFields(isIgnoreUnknownFields());
//從Environment中獲取屬性
Map<String, String> properties = getSubProperties(getPropertySources(), prefix);
// 將屬性MAP轉換爲MutablePropertyValues
MutablePropertyValues propertyValues = new MutablePropertyValues(properties);
// 綁定
relaxedDataBinder.bind(propertyValues);
}
}
經過上面的源碼,能夠看出來,dubbo的配置是一環接着一環,不少時候一個不起眼的地方就是往下走的關鍵代碼,他主要是經過註解的導入配置類,而後經過
BeanDefinitionRegistry生成對應的beanDefintion放入spring容器中。
本文所解析的這些源碼均不涉及dubbo的核心功能,僅僅是講了dubbo啓動以後,如何獲取到配置,若是進行配置裝配,方便你們後續有個好的理解。
有興趣能夠看下一spring的擴展機制,dubbo中都有大量的使用到。
https://nobodyiam.com/2017/02/26/several-ways-to-extend-spring/
本文分享自微信公衆號 - sharedCode(sharedCode)。
若有侵權,請聯繫 support@oschina.cn 刪除。
本文參與「OSC源創計劃」,歡迎正在閱讀的你也加入,一塊兒分享。