前沿
Spring整合dubbo,核心解決三個(gè)問題:
- 解析配置文件,獲取dubbo需要屬性信息
- 找到所有@Service,導(dǎo)出服務(wù)到注冊(cè)中心
- 找到所有@Reference 從注冊(cè)中心獲取實(shí)現(xiàn)服務(wù)并注入
一. 整合核心注解
通過EnableDubbo注解開啟.
@Configuration
@EnableDubbo(scanBasePackages = "org.apache.dubbo.xxx")
@PropertySource("classpath:/spring/dubbo-xxx.properties" )
static class DubboConfiguration {
}
EnableDubbo 接口核心注解 @EnableDubboConfig @DubboComponentScan
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
@EnableDubboConfig
@DubboComponentScan
public @interface EnableDubbo {
... ... ...
}
EnableDubboConfig
@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;
}
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 {};
}
二. dubbo配置處理核心流程

參見Spring容器啟動(dòng)流程,不難找到配置處理流程入口DubboConfigConfigurationRegistrar的registerBeanDefinitions
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
System.out.println("執(zhí)行DubboConfigConfigurationRegistrar");
AnnotationAttributes attributes = AnnotationAttributes.fromMap(
importingClassMetadata.getAnnotationAttributes(EnableDubboConfig.class.getName()));
// multiple 支持,如支持多個(gè)注冊(cè)中心,多個(gè)協(xié)議等
boolean multiple = attributes.getBoolean("multiple");
// Single Config Bindings
registerBeans(registry, DubboConfigConfiguration.Single.class);
if (multiple) { // Since 2.6.6 https://github.com/apache/dubbo/issues/3193
registerBeans(registry, DubboConfigConfiguration.Multiple.class);
}
}
// 無論multiple是否為true,核心都是走registerBeans,該方法時(shí)AnnotatedBeanDefinitionRegistryUtils實(shí)現(xiàn)的,通過AnnotatedBeanDefinitionReader的register方法,解析目標(biāo)類上所有注解,進(jìn)行處理
public static void registerBeans(BeanDefinitionRegistry registry, Class<?>... annotatedClasses) {
... ... ...
AnnotatedBeanDefinitionReader reader = new AnnotatedBeanDefinitionReader(registry);
... ... ...
// 利用Spring中的AnnotatedBeanDefinitionReader來解析annotatedClasses
// 會(huì)解析該類上的注解,然后進(jìn)行處理
reader.register(annotatedClasses);
}
** DubboConfigConfiguration**
Single和Multiple 都是注解EnableDubboConfigBindings,只是前綴和multiple屬性不同。
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),
@EnableDubboConfigBinding(prefix = "dubbo.config-center", type = ConfigCenterBean.class),
@EnableDubboConfigBinding(prefix = "dubbo.metadata-report", type = MetadataReportConfig.class),
@EnableDubboConfigBinding(prefix = "dubbo.metrics", type = MetricsConfig.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),
@EnableDubboConfigBinding(prefix = "dubbo.config-centers", type = ConfigCenterBean.class, multiple = true),
@EnableDubboConfigBinding(prefix = "dubbo.metadata-reports", type = MetadataReportConfig.class, multiple = true),
@EnableDubboConfigBinding(prefix = "dubbo.metricses", type = MetricsConfig.class, multiple = true)
})
public static class Multiple {
}
}
EnableDubboConfigBinding
EnableDubboConfigBinding上導(dǎo)入DubboConfigBindingsRegistrar
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(DubboConfigBindingsRegistrar.class)
public @interface EnableDubboConfigBindings {
/**
* The value of {@link EnableDubboConfigBindings}
*
* @return non-null
*/
EnableDubboConfigBinding[] value();
}
DubboConfigBindingsRegistrar
DubboConfigBindingsRegistrar 實(shí)現(xiàn)了ImportBeanDefinitionRegistrar,會(huì)調(diào)用registerBeanDefinitions,獲取所有的注解,逐個(gè)解析處理。
public class DubboConfigBindingsRegistrar implements ImportBeanDefinitionRegistrar, EnvironmentAware {
private ConfigurableEnvironment environment;
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
System.out.println("執(zhí)行DubboConfigBindingsRegistrar");
AnnotationAttributes attributes = AnnotationAttributes.fromMap(
importingClassMetadata.getAnnotationAttributes(EnableDubboConfigBindings.class.getName()));
// 拿到多個(gè)@EnableDubboConfigBinding注解
AnnotationAttributes[] annotationAttributes = attributes.getAnnotationArray("value");
DubboConfigBindingRegistrar registrar = new DubboConfigBindingRegistrar();
registrar.setEnvironment(environment);
for (AnnotationAttributes element : annotationAttributes) {
// 逐個(gè)解析@EnableDubboConfigBinding注解,比如@EnableDubboConfigBinding(prefix = "dubbo.application", type = ApplicationConfig.class)
registrar.registerBeanDefinitions(element, registry);
}
}
}
逐個(gè)解析EnableDubboConfigBinding
protected void registerBeanDefinitions(AnnotationAttributes attributes, BeanDefinitionRegistry registry) {
// prefix = "dubbo.application"
String prefix = environment.resolvePlaceholders(attributes.getString("prefix"));
// type = ApplicationConfig.class
Class<? extends AbstractConfig> configClass = attributes.getClass("type");
boolean multiple = attributes.getBoolean("multiple");
registerDubboConfigBeans(prefix, configClass, multiple, registry);
}
registerDubboConfigBeans
核心處理方法。按前綴生成不同的beanName。循環(huán)所有beamNames,執(zhí)行
- registerDubboConfigBean
不是真正的注冊(cè)Bean,只是注冊(cè)BeanDefinition。Spring容器啟動(dòng)過程中會(huì)根據(jù)這些BeanDefinition生成相應(yīng)的Bean。
- registerDubboConfigBindingBeanPostProcessor
注冊(cè)后置處理器
private void registerDubboConfigBeans(String prefix,
Class<? extends AbstractConfig> configClass,
boolean multiple,
BeanDefinitionRegistry registry) {
// 從properties文件中根據(jù)前綴拿對(duì)應(yīng)的配置項(xiàng),比如根據(jù)dubbo.application前綴,
// 就可以拿到:
// dubbo.application.name=dubbo-demo-provider-application
// dubbo.application.logger=log4j
Map<String, Object> properties = getSubProperties(environment.getPropertySources(), prefix);
// 如果沒有相關(guān)的配置項(xiàng),則不需要注冊(cè)BeanDefinition
if (CollectionUtils.isEmpty(properties)) {
if (log.isDebugEnabled()) {
log.debug("There is no property for binding to dubbo config class [" + configClass.getName()
+ "] within prefix [" + prefix + "]");
}
return;
}
// 根據(jù)配置項(xiàng)生成beanNames,為什么會(huì)有多個(gè)?
// 普通情況一個(gè)dubbo.application前綴對(duì)應(yīng)一個(gè)ApplicationConfig類型的Bean
// 特殊情況下,比如dubbo.protocols對(duì)應(yīng)了:
// dubbo.protocols.p1.name=dubbo
// dubbo.protocols.p1.port=20880
// dubbo.protocols.p1.host=0.0.0.0
// dubbo.protocols.p2.name=http
// dubbo.protocols.p2.port=8082
// dubbo.protocols.p2.host=0.0.0.0
// 那么就需要對(duì)應(yīng)兩個(gè)ProtocolConfig類型的Bean,那么就需要兩個(gè)beanName:p1和p2
// 這里就是multiple為true或false的區(qū)別,名字的區(qū)別,根據(jù)multiple用來判斷是否從配置項(xiàng)中獲取beanName
// 如果multiple為false,則看有沒有配置id屬性,如果沒有配置則自動(dòng)生成一個(gè)beanName.
Set<String> beanNames = multiple ? resolveMultipleBeanNames(properties) :
Collections.singleton(resolveSingleBeanName(properties, configClass, registry));
for (String beanName : beanNames) {
// 為每個(gè)beanName,注冊(cè)一個(gè)空的BeanDefinition
registerDubboConfigBean(beanName, configClass, registry);
// 為每個(gè)bean注冊(cè)一個(gè)DubboConfigBindingBeanPostProcessor的Bean后置處理器
registerDubboConfigBindingBeanPostProcessor(prefix, beanName, multiple, registry);
}
// 注冊(cè)一個(gè)NamePropertyDefaultValueDubboConfigBeanCustomizer的bean
registerDubboConfigBeanCustomizers(registry);
}
DubboConfigBindingBeanPostProcessor
這個(gè)后置處理器實(shí)現(xiàn)了BeanDefinitionRegistryPostProcessor,在Bean初始化之前Spring調(diào)用postProcessBeforeInitialization,將配置文件中的屬性放入Bean實(shí)例中
public class DubboConfigBindingBeanPostProcessor implements BeanPostProcessor, ApplicationContextAware, InitializingBean
, BeanDefinitionRegistryPostProcessor {
... ... ...
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
// 每個(gè)XxConfig對(duì)應(yīng)一個(gè)BeanPostProcessor,所以每個(gè)DubboConfigBindingBeanPostProcessor只處理對(duì)應(yīng)的beanName
if (this.beanName.equals(beanName) && bean instanceof AbstractConfig) {
AbstractConfig dubboConfig = (AbstractConfig) bean;
// 從properties文件中獲取值,并設(shè)置到dubboConfig對(duì)象中
bind(prefix, dubboConfig);
// 設(shè)置dubboConfig對(duì)象的name屬性,設(shè)置為beanName
customize(beanName, dubboConfig);
}
return bean;
}
... ... ...
}
三. @Service 處理
核心邏輯:
- 擴(kuò)展BeanFactoryBeanPostProcessor,實(shí)現(xiàn)掃描所有@Service,注冊(cè)BeanDefinition
- 通過注冊(cè)的Bean類型ServiceBean 實(shí)現(xiàn)Spring監(jiān)聽器接口,監(jiān)聽容器完成啟動(dòng)。在容器啟動(dòng)后最終執(zhí)行export方法,暴露接口

四. @Reference 處理
類似Autowired 實(shí)現(xiàn),
- 只是實(shí)例化時(shí)傳遞自己關(guān)心的注解
- 實(shí)例化后初始化前(Autowired之前),執(zhí)行 postProcessPropertyValues
- 生成一個(gè)代理對(duì)象,然后注入到屬性中。其中這個(gè)代理對(duì)象時(shí)dubbo的ReferenceConfig 生成的 Invoker, 這個(gè)Invoker 持有注冊(cè)服務(wù)信息,最終完成遠(yuǎn)程RPC調(diào)用

五. 總結(jié)
