一、整合原理
dubbo应用启动类
public class Application {
public static void main(String[] args) throws Exception {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(ProviderConfiguration.class);
context.start();
System.in.read();
}
@Configuration
@EnableDubbo(scanBasePackages = "org.apache.dubbo.demo.provider")
@PropertySource("classpath:/spring/dubbo-provider.properties")
static class ProviderConfiguration {
@Bean
public RegistryConfig registryConfig() {
RegistryConfig registryConfig = new RegistryConfig();
registryConfig.setAddress("zookeeper://127.0.0.1:2181");
return registryConfig;
}
}
}
@PropertySource注解,将dubbo-provider.properties中的配置项添加到Spring容器。‘
@EnableDubbo注解,对指定包下的类进行扫描,扫描@DubboService与@DubboReference注解,并且进行处理
二、EnableDubbo注解
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
@EnableDubboConfig
@DubboComponentScan
public @interface EnableDubbo {
@AliasFor(annotation = DubboComponentScan.class, attribute = "basePackages")
String[] scanBasePackages() default {};
@AliasFor(annotation = DubboComponentScan.class, attribute = "basePackageClasses")
Class<?>[] scanBasePackageClasses() default {};
@AliasFor(annotation = EnableDubboConfig.class, attribute = "multiple")
boolean multipleConfig() default true;
}
利用注解@EnableDubbo引入@EnableDubboConfig、@DubboComponentScan。
分别导入:DubboConfigConfigurationRegistrar、DubboComponentScanRegistrar。都继承Spring的ImportBeanDefinitionRegistrar接口
Spring启动(解析生成BeanDefinition)时,调用ImportBeanDefinitionRegistrar#registerBeanDefinitions方法。
1.1.EnableDubboConfig注解
本质是@Import注解
导入核心类:DubboConfigConfigurationRegistrar
目的:将配置文件中配置项生成Bean对象
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
@Import(DubboConfigConfigurationRegistrar.class)
public @interface EnableDubboConfig {
boolean multiple() default true;
}
1.2.DubboConfigConfigurationRegistrar类
主要作用就是对propties文件进行解析,根据不同的配置项生成对应类型的Bean对象。
Spring启动(解析生成BeanDefinition)时,调用DubboConfigConfigurationRegistrar的registerBeanDefinitions方法。读取DubboConfigConfiguration.Single.class、DubboConfigConfiguration.Multiple.class 注解
public class DubboConfigConfigurationRegistrar implements ImportBeanDefinitionRegistrar, ApplicationContextAware {
private ConfigurableApplicationContext applicationContext;
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
AnnotationAttributes attributes = AnnotationAttributes.fromMap(
importingClassMetadata.getAnnotationAttributes(EnableDubboConfig.class.getName()));
//注解 @EnableDubboConfig multiple属性 默认true
boolean multiple = attributes.getBoolean("multiple");
registerBeans(registry, DubboConfigConfiguration.Single.class);
if (multiple) { // Since 2.6.6 https://github.com/apache/dubbo/issues/3193
registerBeans(registry, DubboConfigConfiguration.Multiple.class);
}
// Since 2.7.6
registerCommonBeans(registry);
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
if (!(applicationContext instanceof ConfigurableApplicationContext)) {
throw new IllegalArgumentException("The argument of ApplicationContext must be ConfigurableApplicationContext");
}
this.applicationContext = (ConfigurableApplicationContext) applicationContext;
}
}
1.2.1.DubboConfigConfiguration类
public class DubboConfigConfiguration {
/**
* Single Dubbo {@link AbstractConfig Config} Bean Binding
* 对应而配置文件中配置:
* dubbo.application.name=dubbo-demo-annotation-provider
* dubbo.protocol.name=dubbo
*
* 注解中:prefix 标记配置前缀。type 标记配置对应的配置类
*/
@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),
@EnableConfigurationBeanBinding(prefix = "dubbo.ssl", type = SslConfig.class)
})
public static class Single {
}
/**
* Multiple Dubbo {@link AbstractConfig Config} Bean Binding
* 对应而配置文件中配置:
*
* dubbo.protocols.dubbo.name=dubbo
* dubbo.protocols.dubbo.port=20880
*/
@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 {
}
}
1.2.2.EnableConfigurationBeanBindings注解
@EnableConfigurationBeanBindings本质是@Import注解。用于导入ConfigurationBeanBindingsRegister(在阿里的Spring-context-support包中)。
ConfigurationBeanBindingsRegister会处理注解@EnableConfigurationBeanBinding。
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import({ConfigurationBeanBindingsRegister.class})
public @interface EnableConfigurationBeanBindings {
EnableConfigurationBeanBinding[] value();
}
1.2.3.ConfigurationBeanBindingsRegister
主要方法:registerDubboConfigBeans()方法。
主要功能:
- 解析properties文件,获取用户配置的properties文件内容。
- 生成对应类型的BeanDefinition实例。
- 根据properties文件的每个配置项为BeanDefinition实例进行赋值。
- 并向Spring容器注册ConfigurationBeanBindingsPostProcessor。
- 判断是否为EnableConfigurationBeanBinding类型实例。
- 根据beanName获取BeanDefinition,取出配置内容,为配置项实例赋值
例如:
@EnableConfigurationBeanBinding(prefix = “dubbo.application”, type = ApplicationConfig.class),
前缀为”dubbo.application”的配置项,会生成一个ApplicationConfig类型的BeanDefinition。
前缀为”dubbo.protocols”的配置项,会生成两个ProtocolConfig类型的BeanDefinition,两个BeanDefinition的beanName分别为dubbo和rest(或者p1和p2)。
最终配置参数都会生成对象。
2.1.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 {};
}
导入核心类:DubboComponentScanRegistrar。将Dubbo类生成BeanDefinition对象,从而借助Spring生成Dubbo对象
2.2.DubboComponentScanRegistrar
向Spring容器注入
- ServiceClassPostProcessor
- ReferenceAnnotationBeanPostProcessor
- DubboConfigAliasPostProcessor
- DubboApplicationListenerRegistrar
- DubboConfigDefaultPropertyValueBeanPostProcessor
DubboConfigEarlyRegistrationPostProcessor ```java public class DubboComponentScanRegistrar implements ImportBeanDefinitionRegistrar {
@Override public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
Set<String> packagesToScan = getPackagesToScan(importingClassMetadata);
//1.注册 ServiceClassPostProcessor
registerServiceClassPostProcessor(packagesToScan, registry);
// @since 2.7.6 Register the common beans
//2.注册:ReferenceAnnotationBeanPostProcessor
registerCommonBeans(registry);
}
/**
- Registers {@link ServiceClassPostProcessor} *
- @param packagesToScan packages to scan without resolving placeholders
- @param registry {@link BeanDefinitionRegistry}
@since 2.5.8 */ private void registerServiceClassPostProcessor(Set
packagesToScan, BeanDefinitionRegistry registry) { BeanDefinitionBuilder builder = rootBeanDefinition(ServiceClassPostProcessor.class); builder.addConstructorArgValue(packagesToScan); builder.setRole(BeanDefinition.ROLE_INFRASTRUCTURE); AbstractBeanDefinition beanDefinition = builder.getBeanDefinition(); BeanDefinitionReaderUtils.registerWithGeneratedName(beanDefinition, registry);
}
private Set
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
packagesToScan = new LinkedHashSet (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; }
2.2.1.ServiceClassPostProcessor
本质是一个BeanDefinitionRegistryPostProcessor,是用来注册BeanDefinition的。
主要作用:
- 实例化扫描器(DubboClassPathBeanDefinitionScanner),扫描指定路径下类,并解析成BeanDefinition。
- 向Spring容器注册BeanDefinition(利用Spring完成实例化)。
- 进行服务导出(暴露)准备(注册ServiceBeanDefinition)。
- 从BeanDefinition中获取Class全类名,并生成Class对象。
- 获取Class对象上Dubbo的@Service、@DubboService注解对象,并解析注解属性。
- 生成serviceBeanDefinition(本质仍然是BeanDefinition)。
- 生成ServiceBeanName(interfaceClassName+version+group)。
- 将serviceBeanDefinition注册到Spring容器(利用Spring实例化serviceBeanDefinition,完成服务暴露)。
- ServiceBean实例通过ref属性,关联服务实现类。
总结:一个dubbo服务类会注册两个BeanDefinition。(一个用于实例化对象?、一个(serviceBean)用于对外暴露服务)。
2.2.1.1.DubboClassPathBeanDefinitionScanner
Dubbo自定义的扫描器,继承Spring的ClassPathBeanDefinitionScanner
DubboClassPathBeanDefinitionScanner仅将父类中useDefaultFilters设置为false。
主要是因为Dubbo中的@DubboService、@Service注解是Dubbo自定义的,并没有用@Component注解(Dubbo不是一定要结合Spring才能用),为了能利用Spring的扫描逻辑,需要把useDefaultFilters设置为false。
2.2.1.2.ServiceBean
ServiceBean表示一个Dubbo服务,它有一些参数,比如:
- ref,表示dubbo服务的具体实现类。
- interface,表示服务的接口
- parameters,表示服务的参数(@Service注解中所配置的信息)
- application,表示服务所属的应用
- protocols,表示服务所使用的协议(由配置文件配置)
-
2.2.2.ReferenceAnnotationBeanPostProcessor
继承:InstantiationAwareBeanPostProcessor�。
在Spring属性注入步骤(AbstractAutowireCapableBeanFactory#populateBean#populateBean):会循环调用所有InstantiationAwareBeanPostProcessor
用于处理@DubboReference、@Reference注解,利用Spring完成依赖注入。 查找注入点,即:@DubboReference、@Reference注解的属性或方法都是注入点。
- 某个Bean找到所有注入点之后,进行注入,即:给属性或给set方法赋值。
- 赋值前获得代理对象;即会调用ReferenceAnnotationBeanPostProcessor#doGetInjectedBean()方法,构建referenceBean 实例,调用eferenceBean#get()方法,得到当前属性所对应的服务接口的代理对象。
- 基于 @Service、@DubboService 生成提供者名(referencedBeanName)。即:服务【提供者】对应的ServiceBean的beanName
- 基于 @Reference、@DubboReference 生成消费者名(referenceBeanName)。即:服务【消费者】对应的ServiceBean的beanName
- 服务提供者名 与 服务消费者名建立映射关系
- 根据referenceBeanName从referenceBeanCache获取对应的ReferenceBean.如果为空。创建代理并缓存。
- 判断当前Spring容器是否存在 referencedBeanName 服务提供者实例。
- 执行服务发布。
- 将 referenceBean 实例,添加到Spring单例池。用于支持Spring @Autowire 注解�(referenceBean本质是FactoryBean)
- referenceBean实例,通过get与服务实例关联
2.2.3.DubboApplicationListenerRegistrar
- 注册监听器:DubboBootstrapApplicationListener;启动dubbo容器。统一进行dubbo服务发布。(具体在服务导出中介绍)
- 注册监听器:DubboLifecycleComponentApplicationListener;调用初始化方法(或销毁方法)