一、整合原理

dubbo应用启动类

  1. public class Application {
  2. public static void main(String[] args) throws Exception {
  3. AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(ProviderConfiguration.class);
  4. context.start();
  5. System.in.read();
  6. }
  7. @Configuration
  8. @EnableDubbo(scanBasePackages = "org.apache.dubbo.demo.provider")
  9. @PropertySource("classpath:/spring/dubbo-provider.properties")
  10. static class ProviderConfiguration {
  11. @Bean
  12. public RegistryConfig registryConfig() {
  13. RegistryConfig registryConfig = new RegistryConfig();
  14. registryConfig.setAddress("zookeeper://127.0.0.1:2181");
  15. return registryConfig;
  16. }
  17. }
  18. }

@PropertySource注解,将dubbo-provider.properties中的配置项添加到Spring容器。‘
@EnableDubbo注解,对指定包下的类进行扫描,扫描@DubboService与@DubboReference注解,并且进行处理

二、EnableDubbo注解

  1. @Target({ElementType.TYPE})
  2. @Retention(RetentionPolicy.RUNTIME)
  3. @Inherited
  4. @Documented
  5. @EnableDubboConfig
  6. @DubboComponentScan
  7. public @interface EnableDubbo {
  8. @AliasFor(annotation = DubboComponentScan.class, attribute = "basePackages")
  9. String[] scanBasePackages() default {};
  10. @AliasFor(annotation = DubboComponentScan.class, attribute = "basePackageClasses")
  11. Class<?>[] scanBasePackageClasses() default {};
  12. @AliasFor(annotation = EnableDubboConfig.class, attribute = "multiple")
  13. boolean multipleConfig() default true;
  14. }

利用注解@EnableDubbo引入@EnableDubboConfig、@DubboComponentScan。
分别导入:DubboConfigConfigurationRegistrar、DubboComponentScanRegistrar。都继承Spring的ImportBeanDefinitionRegistrar接口
Spring启动(解析生成BeanDefinition)时,调用ImportBeanDefinitionRegistrar#registerBeanDefinitions方法。

1.1.EnableDubboConfig注解

本质是@Import注解
导入核心类:DubboConfigConfigurationRegistrar
目的:将配置文件中配置项生成Bean对象

  1. @Target({ElementType.TYPE})
  2. @Retention(RetentionPolicy.RUNTIME)
  3. @Inherited
  4. @Documented
  5. @Import(DubboConfigConfigurationRegistrar.class)
  6. public @interface EnableDubboConfig {
  7. boolean multiple() default true;
  8. }

1.2.DubboConfigConfigurationRegistrar类

主要作用就是对propties文件进行解析,根据不同的配置项生成对应类型的Bean对象
Spring启动(解析生成BeanDefinition)时,调用DubboConfigConfigurationRegistrar的registerBeanDefinitions方法。读取DubboConfigConfiguration.Single.class、DubboConfigConfiguration.Multiple.class 注解
image.png

  1. public class DubboConfigConfigurationRegistrar implements ImportBeanDefinitionRegistrar, ApplicationContextAware {
  2. private ConfigurableApplicationContext applicationContext;
  3. @Override
  4. public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
  5. AnnotationAttributes attributes = AnnotationAttributes.fromMap(
  6. importingClassMetadata.getAnnotationAttributes(EnableDubboConfig.class.getName()));
  7. //注解 @EnableDubboConfig multiple属性 默认true
  8. boolean multiple = attributes.getBoolean("multiple");
  9. registerBeans(registry, DubboConfigConfiguration.Single.class);
  10. if (multiple) { // Since 2.6.6 https://github.com/apache/dubbo/issues/3193
  11. registerBeans(registry, DubboConfigConfiguration.Multiple.class);
  12. }
  13. // Since 2.7.6
  14. registerCommonBeans(registry);
  15. }
  16. @Override
  17. public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
  18. if (!(applicationContext instanceof ConfigurableApplicationContext)) {
  19. throw new IllegalArgumentException("The argument of ApplicationContext must be ConfigurableApplicationContext");
  20. }
  21. this.applicationContext = (ConfigurableApplicationContext) applicationContext;
  22. }
  23. }

1.2.1.DubboConfigConfiguration类

  1. public class DubboConfigConfiguration {
  2. /**
  3. * Single Dubbo {@link AbstractConfig Config} Bean Binding
  4. * 对应而配置文件中配置:
  5. * dubbo.application.name=dubbo-demo-annotation-provider
  6. * dubbo.protocol.name=dubbo
  7. *
  8. * 注解中:prefix 标记配置前缀。type 标记配置对应的配置类
  9. */
  10. @EnableConfigurationBeanBindings({
  11. @EnableConfigurationBeanBinding(prefix = "dubbo.application", type = ApplicationConfig.class),
  12. @EnableConfigurationBeanBinding(prefix = "dubbo.module", type = ModuleConfig.class),
  13. @EnableConfigurationBeanBinding(prefix = "dubbo.registry", type = RegistryConfig.class),
  14. @EnableConfigurationBeanBinding(prefix = "dubbo.protocol", type = ProtocolConfig.class),
  15. @EnableConfigurationBeanBinding(prefix = "dubbo.monitor", type = MonitorConfig.class),
  16. @EnableConfigurationBeanBinding(prefix = "dubbo.provider", type = ProviderConfig.class),
  17. @EnableConfigurationBeanBinding(prefix = "dubbo.consumer", type = ConsumerConfig.class),
  18. @EnableConfigurationBeanBinding(prefix = "dubbo.config-center", type = ConfigCenterBean.class),
  19. @EnableConfigurationBeanBinding(prefix = "dubbo.metadata-report", type = MetadataReportConfig.class),
  20. @EnableConfigurationBeanBinding(prefix = "dubbo.metrics", type = MetricsConfig.class),
  21. @EnableConfigurationBeanBinding(prefix = "dubbo.ssl", type = SslConfig.class)
  22. })
  23. public static class Single {
  24. }
  25. /**
  26. * Multiple Dubbo {@link AbstractConfig Config} Bean Binding
  27. * 对应而配置文件中配置:
  28. *
  29. * dubbo.protocols.dubbo.name=dubbo
  30. * dubbo.protocols.dubbo.port=20880
  31. */
  32. @EnableConfigurationBeanBindings({
  33. @EnableConfigurationBeanBinding(prefix = "dubbo.applications", type = ApplicationConfig.class, multiple = true),
  34. @EnableConfigurationBeanBinding(prefix = "dubbo.modules", type = ModuleConfig.class, multiple = true),
  35. @EnableConfigurationBeanBinding(prefix = "dubbo.registries", type = RegistryConfig.class, multiple = true),
  36. @EnableConfigurationBeanBinding(prefix = "dubbo.protocols", type = ProtocolConfig.class, multiple = true),
  37. @EnableConfigurationBeanBinding(prefix = "dubbo.monitors", type = MonitorConfig.class, multiple = true),
  38. @EnableConfigurationBeanBinding(prefix = "dubbo.providers", type = ProviderConfig.class, multiple = true),
  39. @EnableConfigurationBeanBinding(prefix = "dubbo.consumers", type = ConsumerConfig.class, multiple = true),
  40. @EnableConfigurationBeanBinding(prefix = "dubbo.config-centers", type = ConfigCenterBean.class, multiple = true),
  41. @EnableConfigurationBeanBinding(prefix = "dubbo.metadata-reports", type = MetadataReportConfig.class, multiple = true),
  42. @EnableConfigurationBeanBinding(prefix = "dubbo.metricses", type = MetricsConfig.class, multiple = true)
  43. })
  44. public static class Multiple {
  45. }
  46. }

1.2.2.EnableConfigurationBeanBindings注解

@EnableConfigurationBeanBindings本质是@Import注解。用于导入ConfigurationBeanBindingsRegister(在阿里的Spring-context-support包中)。
ConfigurationBeanBindingsRegister会处理注解@EnableConfigurationBeanBinding。

  1. @Target({ElementType.TYPE})
  2. @Retention(RetentionPolicy.RUNTIME)
  3. @Documented
  4. @Import({ConfigurationBeanBindingsRegister.class})
  5. public @interface EnableConfigurationBeanBindings {
  6. EnableConfigurationBeanBinding[] value();
  7. }

1.2.3.ConfigurationBeanBindingsRegister

主要方法:registerDubboConfigBeans()方法。
主要功能:

  1. 解析properties文件,获取用户配置的properties文件内容。
  2. 生成对应类型的BeanDefinition实例。
  3. 根据properties文件的每个配置项为BeanDefinition实例进行赋值。
  4. 并向Spring容器注册ConfigurationBeanBindingsPostProcessor
    1. 判断是否为EnableConfigurationBeanBinding类型实例。
    2. 根据beanName获取BeanDefinition,取出配置内容,为配置项实例赋值

例如:
image.png
@EnableConfigurationBeanBinding(prefix = “dubbo.application”, type = ApplicationConfig.class),
前缀为”dubbo.application”的配置项,会生成一个ApplicationConfig类型的BeanDefinition。
前缀为”dubbo.protocols”的配置项,会生成个ProtocolConfig类型的BeanDefinition,两个BeanDefinition的beanName分别为dubbo和rest(或者p1和p2)。
最终配置参数都会生成对象。

2.1.DubboComponentScan注解

  1. @Target(ElementType.TYPE)
  2. @Retention(RetentionPolicy.RUNTIME)
  3. @Documented
  4. @Import(DubboComponentScanRegistrar.class)
  5. public @interface DubboComponentScan {
  6. /**
  7. * Alias for the {@link #basePackages()} attribute. Allows for more concise annotation
  8. * declarations e.g.: {@code @DubboComponentScan("org.my.pkg")} instead of
  9. * {@code @DubboComponentScan(basePackages="org.my.pkg")}.
  10. *
  11. * @return the base packages to scan
  12. */
  13. String[] value() default {};
  14. /**
  15. * Base packages to scan for annotated @Service classes. {@link #value()} is an
  16. * alias for (and mutually exclusive with) this attribute.
  17. * <p>
  18. * Use {@link #basePackageClasses()} for a type-safe alternative to String-based
  19. * package names.
  20. *
  21. * @return the base packages to scan
  22. */
  23. String[] basePackages() default {};
  24. /**
  25. * Type-safe alternative to {@link #basePackages()} for specifying the packages to
  26. * scan for annotated @Service classes. The package of each class specified will be
  27. * scanned.
  28. *
  29. * @return classes from the base packages to scan
  30. */
  31. Class<?>[] basePackageClasses() default {};
  32. }

导入核心类:DubboComponentScanRegistrar。将Dubbo类生成BeanDefinition对象,从而借助Spring生成Dubbo对象

2.2.DubboComponentScanRegistrar

向Spring容器注入

  1. ServiceClassPostProcessor
  2. ReferenceAnnotationBeanPostProcessor
  3. DubboConfigAliasPostProcessor
  4. DubboApplicationListenerRegistrar
  5. DubboConfigDefaultPropertyValueBeanPostProcessor
  6. DubboConfigEarlyRegistrationPostProcessor ```java public class DubboComponentScanRegistrar implements ImportBeanDefinitionRegistrar {

    @Override public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {

    1. Set<String> packagesToScan = getPackagesToScan(importingClassMetadata);
    2. //1.注册 ServiceClassPostProcessor
    3. registerServiceClassPostProcessor(packagesToScan, registry);
    4. // @since 2.7.6 Register the common beans
    5. //2.注册:ReferenceAnnotationBeanPostProcessor
    6. 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(

      1. 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) {

      1. packagesToScan.add(ClassUtils.getPackageName(basePackageClass));

      } if (packagesToScan.isEmpty()) {

      1. return Collections.singleton(ClassUtils.getPackageName(metadata.getClassName()));

      } return packagesToScan; }

} ```

2.2.1.ServiceClassPostProcessor

image.png
本质是一个BeanDefinitionRegistryPostProcessor,是用来注册BeanDefinition的
主要作用:

  1. 实例化扫描器(DubboClassPathBeanDefinitionScanner),扫描指定路径下类,并解析成BeanDefinition。
  2. 向Spring容器注册BeanDefinition(利用Spring完成实例化)。
  3. 进行服务导出(暴露)准备(注册ServiceBeanDefinition)。
    1. 从BeanDefinition中获取Class全类名,并生成Class对象。
    2. 获取Class对象上Dubbo的@Service、@DubboService注解对象,并解析注解属性。
    3. 生成serviceBeanDefinition(本质仍然是BeanDefinition)。
    4. 生成ServiceBeanName(interfaceClassName+version+group)。
    5. 将serviceBeanDefinition注册到Spring容器(利用Spring实例化serviceBeanDefinition,完成服务暴露)。
    6. 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服务,它有一些参数,比如:

  1. ref,表示dubbo服务的具体实现类
  2. interface,表示服务的接口
  3. parameters,表示服务的参数(@Service注解中所配置的信息)
  4. application,表示服务所属的应用
  5. protocols,表示服务所使用的协议(由配置文件配置
  6. registries,表示服务所要注册的注册中心

    2.2.2.ReferenceAnnotationBeanPostProcessor

    继承:InstantiationAwareBeanPostProcessor�。
    在Spring属性注入步骤(AbstractAutowireCapableBeanFactory#populateBean#populateBean):会循环调用所有InstantiationAwareBeanPostProcessor
    截屏2022-11-09 下午5.16.53.png
    用于处理@DubboReference、@Reference注解,利用Spring完成依赖注入。

  7. 查找注入点,即:@DubboReference、@Reference注解的属性或方法都是注入点。

  8. 某个Bean找到所有注入点之后,进行注入,即:给属性或给set方法赋值。
  9. 赋值前获得代理对象;即会调用ReferenceAnnotationBeanPostProcessor#doGetInjectedBean()方法,构建referenceBean 实例,调用eferenceBean#get()方法,得到当前属性所对应的服务接口的代理对象
    1. 基于 @Service、@DubboService 生成提供者名(referencedBeanName)。即:服务【提供者】对应的ServiceBean的beanName
    2. 基于 @Reference、@DubboReference 生成消费者名(referenceBeanName)。即:服务【消费者】对应的ServiceBean的beanName
    3. 服务提供者名 与 服务消费者名建立映射关系
    4. 根据referenceBeanName从referenceBeanCache获取对应的ReferenceBean.如果为空。创建代理并缓存。
    5. 判断当前Spring容器是否存在 referencedBeanName 服务提供者实例。
    6. 执行服务发布
    7. 将 referenceBean 实例,添加到Spring单例池。用于支持Spring @Autowire 注解�(referenceBean本质是FactoryBean)
    8. referenceBean实例,通过get与服务实例关联

      2.2.3.DubboApplicationListenerRegistrar

  • 注册监听器:DubboBootstrapApplicationListener;启动dubbo容器。统一进行dubbo服务发布。(具体在服务导出中介绍)
  • 注册监听器:DubboLifecycleComponentApplicationListener;调用初始化方法(或销毁方法)