Dubbo(九):注解配置

1. 概述

在 Dubbo 提供的几种方式中,注解配置慢慢变成大家最常用的方式。

如果胖友不熟悉,可以查看如下文档:

  • 《Dubbo 用户指南 —— 注解配置》
  • 《在 Dubbo 中使用注解》
  • 《Dubbo 注解驱动(Annotation-Driven)》

2. 使用示例

我们来看看 dubbo-demo-annotation 项目下的 dubbo-demo-annotation-provider 子项目提供的 Dubbo Provider 示例。代码如下:

// Application.java

public class Application {

    /**
     * In order to make sure multicast registry works, need to specify '-Djava.net.preferIPv4Stack=true' before
     * launch the 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") // <1>
    @PropertySource("classpath:/spring/dubbo-provider.properties") // <2>
    static class ProviderConfiguration {

        @Bean // <3>
        public RegistryConfig registryConfig() {
            RegistryConfig registryConfig = new RegistryConfig();
            registryConfig.setAddress("multicast://224.5.6.7:1234");
            return registryConfig;
        }

    }

}
  • <1> 处,使用 @EnableDubbo 注解,配置扫描 "org.apache.dubbo.demo.provider" 目录下的 @Service 和 @Reference Bean 对象。
  • <2> 处,使用 @PropertySource 注解,导入 "classpath:/spring/dubbo-provider.properties" 配置文件。
  • <3> 处,通过 @Bean 注解方法,创建 RegistryConfig Bean 对象,即注册中心。
  • 通过使用 Java Config + 注解的方式,相比 XML 来说,会更加熟悉一些~

下面,我们就来看看具体的源码落。本文涉及的类,主要如下图所示:Dubbo(九):注解配置_第1张图片

3. @EnableDubbo

org.apache.dubbo.config.spring.context.annotation.@EnableDubbo 注解,是 @EnableDubboConfig 和 @DubboComponentScan的组合注解,使用时更加便利。代码如下:

// EnableDubbo.java

/**
 * Enables Dubbo components as Spring Beans, equals
 * {@link DubboComponentScan} and {@link EnableDubboConfig} combination.
 * 

* Note : {@link EnableDubbo} must base on Spring Framework 4.2 and above * * @see DubboComponentScan * @see EnableDubboConfig * @since 2.5.8 */ @Target({ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Inherited @Documented @EnableDubboConfig // 开启 Dubbo Config @DubboComponentScan // 扫描 Dubbo @Service 和 @Reference Bean public @interface EnableDubbo { /** * 配置 @DubboComponentScan 注解,扫描的包 * * Base packages to scan for annotated @Service classes. *

* Use {@link #scanBasePackageClasses()} for a type-safe alternative to String-based * package names. * * @return the base packages to scan * @see DubboComponentScan#basePackages() */ @AliasFor(annotation = DubboComponentScan.class, attribute = "basePackages") String[] scanBasePackages() default {}; /** * 配置 @DubboComponentScan 注解,扫描的类 * * Type-safe alternative to {@link #scanBasePackages()} 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 * @see DubboComponentScan#basePackageClasses */ @AliasFor(annotation = DubboComponentScan.class, attribute = "basePackageClasses") Class[] scanBasePackageClasses() default {}; /** * 配置 @EnableDubboConfig 注解,配置是否绑定到多个 Spring Bean 上 * * It indicates whether {@link AbstractConfig} binding to multiple Spring Beans. * * @return the default value is false * @see EnableDubboConfig#multiple() */ @AliasFor(annotation = EnableDubboConfig.class, attribute = "multiple") boolean multipleConfig() default false; }

  • 注意看下具体的注释。

通过 @EnableDubbo 可以在指定的包名下(通过 scanBasePackages 属性),或者指定的类中(通过 scanBasePackageClasses属性)扫描 Dubbo 的服务提供者(以 @Service 注解)以及 Dubbo 的服务消费者(以 @Reference 注解)。

扫描到 Dubbo 的服务提供方和消费者之后,对其做相应的组装并初始化,并最终完成服务暴露或者引用的工作。

4. @EnableDubboConfig

org.apache.dubbo.config.spring.context.annotation.@EnableDubboConfig 注解,开启 Dubbo 配置。代码如下:

// EnableDubboConfig.java

/**
 * As  a convenient and multiple {@link EnableDubboConfigBinding}
 * in default behavior , is equal to single bean bindings with below convention prefixes of properties:
 * 
    *
  • {@link ApplicationConfig} binding to property : "dubbo.application"
  • *
  • {@link ModuleConfig} binding to property : "dubbo.module"
  • *
  • {@link RegistryConfig} binding to property : "dubbo.registry"
  • *
  • {@link ProtocolConfig} binding to property : "dubbo.protocol"
  • *
  • {@link MonitorConfig} binding to property : "dubbo.monitor"
  • *
  • {@link ProviderConfig} binding to property : "dubbo.provider"
  • *
  • {@link ConsumerConfig} binding to property : "dubbo.consumer"
  • *
*

* In contrast, on multiple bean bindings that requires to set {@link #multiple()} to be true : *

    *
  • {@link ApplicationConfig} binding to property : "dubbo.applications"
  • *
  • {@link ModuleConfig} binding to property : "dubbo.modules"
  • *
  • {@link RegistryConfig} binding to property : "dubbo.registries"
  • *
  • {@link ProtocolConfig} binding to property : "dubbo.protocols"
  • *
  • {@link MonitorConfig} binding to property : "dubbo.monitors"
  • *
  • {@link ProviderConfig} binding to property : "dubbo.providers"
  • *
  • {@link ConsumerConfig} binding to property : "dubbo.consumers"
  • *
* * @see EnableDubboConfigBinding * @see DubboConfigConfiguration * @see DubboConfigConfigurationSelector * @since 2.5.8 */ @Target({ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Inherited @Documented @Import(DubboConfigConfigurationRegistrar.class) public @interface EnableDubboConfig { /** * It indicates whether binding to multiple Spring Beans. * * 配置是否绑定到多个 Spring Bean 上 * * @return the default value is false * @revised 2.5.9 */ boolean multiple() default false; }
  • 关于 multiple 属性,可能第一眼会有点懵逼,那咋整呢?
    • 第一步,可以看看 《Dubbo 新编程模型之外部化配置 —— @EnableDubboConfig》 对 @EnableDubboConfig 注解的介绍。
    • 第二步,我们在接下来会看具体的源码,会更易懂一些。
  • @Import(DubboConfigConfigurationRegistrar.class) 注解,表明使用 DubboConfigConfigurationRegistrar 类进行导入。详细的,我们继续来看 「4.1 DubboConfigConfigurationRegistrar」 。

4.1 DubboConfigConfigurationRegistrar

org.apache.dubbo.config.spring.context.annotation.DubboConfigConfigurationRegistrar ,实现 ImportBeanDefinitionRegistrar 接口,处理 @EnableDubboConfig 注解,注册相应的 DubboConfigConfiguration 到 Spring 容器中。代码如下:

// DubboConfigConfigurationRegistrar.java

/**
 * Dubbo {@link AbstractConfig Config} {@link ImportBeanDefinitionRegistrar register}, which order can be configured
 *
 * @see EnableDubboConfig
 * @see DubboConfigConfiguration
 * @see Ordered
 * @since 2.5.8
 */
public class DubboConfigConfigurationRegistrar implements ImportBeanDefinitionRegistrar {

    @Override
    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
        // 获得 @EnableDubboConfig 注解的属性
        AnnotationAttributes attributes = AnnotationAttributes.fromMap(importingClassMetadata.getAnnotationAttributes(EnableDubboConfig.class.getName()));
        // 获得 multiple 属性
        boolean multiple = attributes.getBoolean("multiple");
        // 如果为 true ,则注册 DubboConfigConfiguration.Multiple Bean 对象
        if (multiple) {
            AnnotatedBeanDefinitionRegistryUtils.registerBeans(registry, DubboConfigConfiguration.Multiple.class);
        // 如果为 false ,则注册 DubboConfigConfiguration.Single Bean 对象
        } else {
            AnnotatedBeanDefinitionRegistryUtils.registerBeans(registry, DubboConfigConfiguration.Single.class);
        }
    }

}

// AnnotatedBeanDefinitionRegistryUtils.java

public static void registerBeans(BeanDefinitionRegistry registry, Class... annotatedClasses) {
    if (ObjectUtils.isEmpty(annotatedClasses)) {
        return;
    }
    boolean debugEnabled = logger.isDebugEnabled();
    // 创建 AnnotatedBeanDefinitionReader 对象
    AnnotatedBeanDefinitionReader reader = new AnnotatedBeanDefinitionReader(registry);
    if (debugEnabled) {
        logger.debug(registry.getClass().getSimpleName() + " will register annotated classes : " + Arrays.asList(annotatedClasses) + " .");
    }
    // 注册
    reader.register(annotatedClasses);
}
  • 根据 @EnableDubboConfig 注解上的 multiple 属性的不同,创建 DubboConfigConfiguration.Multiple 或 DubboConfigConfiguration.Single 对象,注册到 Spring 容器中。

4.2 DubboConfigConfiguration

org.apache.dubbo.config.spring.beans.factory.annotation.DubboConfigConfiguration ,Dubbo AbstractConfig 配置类。代码如下:

// DubboConfigConfiguration.java

/**
 * Dubbo {@link AbstractConfig Config} {@link Configuration}
 *
 * @see Configuration
 * @see EnableDubboConfigBindings
 * @see EnableDubboConfigBinding
 * @see ApplicationConfig
 * @see ModuleConfig
 * @see RegistryConfig
 * @see ProtocolConfig
 * @see MonitorConfig
 * @see ProviderConfig
 * @see ConsumerConfig
 * @see org.apache.dubbo.config.ConfigCenterConfig
 * @since 2.5.8
 */
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)
    })
    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)
    })
    public static class Multiple {
    }

}
  • 乍眼一看,就是 Single 和 Multiple 内部类。其上都有 @@EnableDubboConfigBindings 和 @EnableDubboConfigBinding 注解。
    • 前者 Single ,其上的注解,prefix 都是单数。
    • 后者 Multiple ,其上的注解,prefix 都是复数,且有 multiple = true 。
  • 那么会有什么效果呢?我们继续往 「4.3 @@EnableDubboConfigBindings」 和 「4.4 @@EnableDubboConfigBinding」 看。

4.3 @EnableDubboConfigBindings

org.apache.dubbo.config.spring.context.annotation.@EnableDubboConfigBindings 注解,是 @EnableDubboConfigBinding 注解的数组。代码如下:

// EnableDubboConfigBindings.java

/**
 * Multiple {@link EnableDubboConfigBinding} {@link Annotation}
 *
 * @since 2.5.8
 * @see EnableDubboConfigBinding
 */
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(DubboConfigBindingsRegistrar.class)
public @interface EnableDubboConfigBindings {

    /**
     * The value of {@link EnableDubboConfigBindings}
     *
     * @return non-null
     */
    EnableDubboConfigBinding[] value();

}
  • @Import(DubboConfigBindingsRegistrar.class) 注解,表明使用 DubboConfigBindingsRegistrar 类进行导入。详细的,我们继续来看 「4.3.1 DubboConfigBindingsRegistrar」 。

4.3.1 DubboConfigBindingsRegistrar

org.apache.dubbo.config.spring.context.annotation.DubboConfigBindingsRegistrar ,实现 ImportBeanDefinitionRegistrar、EnvironmentAware 接口,处理 @EnableDubboConfigBindings 注解,注册相应的 Dubbo AbstractConfig 到 Spring 容器中。代码如下:

// DubboConfigBindingsRegistrar.java

/**
 * {@link AbstractConfig Dubbo Config} binding Bean registrar for {@link EnableDubboConfigBindings}
 *
 * @see EnableDubboConfigBindings
 * @see DubboConfigBindingRegistrar
 * @since 2.5.8
 */
public class DubboConfigBindingsRegistrar implements ImportBeanDefinitionRegistrar, EnvironmentAware {

    private ConfigurableEnvironment environment;

    @Override
    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
        // <1.1> 获得 @EnableDubboConfigBindings 注解
        AnnotationAttributes attributes = AnnotationAttributes.fromMap(importingClassMetadata.getAnnotationAttributes(EnableDubboConfigBindings.class.getName()));
        // <1.2> 获得内部的 @EnableDubboConfigBinding 注解的数组
        AnnotationAttributes[] annotationAttributes = attributes.getAnnotationArray("value");
        // <2> 创建 DubboConfigBindingRegistrar 对象,并设置 environment 属性
        DubboConfigBindingRegistrar registrar = new DubboConfigBindingRegistrar();
        registrar.setEnvironment(environment);
        // <3> 遍历 annotationAttributes 数组,使用 registrar 进行逐个 @EnableDubboConfigBinding 注解的注册对应的 Bean
        for (AnnotationAttributes element : annotationAttributes) {
            registrar.registerBeanDefinitions(element, registry);
        }
    }

    @Override
    public void setEnvironment(Environment environment) {
        Assert.isInstanceOf(ConfigurableEnvironment.class, environment);
        this.environment = (ConfigurableEnvironment) environment;
    }

}
  • <1.1><1.2> 处,获得 @EnableDubboConfigBindings 注解,从而后面获得内部的 @EnableDubboConfigBinding 注解的数组。
  • <2> 处,创建 DubboConfigBindingRegistrar 对象,并设置 environment 属性。
  • <3> 处,遍历 annotationAttributes 数组,使用 registrar ,调用 DubboConfigBindingRegistrar#registerBeanDefinitions(AnnotationAttributes attributes, BeanDefinitionRegistry registry) 方法,进行逐个 @EnableDubboConfigBinding 注解的注册对应的 Bean 。
  • 在下文中,我们会看到 DubboConfigBindingRegistrar 本来就是用来处理 EnableDubboConfigBinding 注解。

4.4 @EnableDubboConfigBinding

org.apache.dubbo.config.spring.context.annotation.@EnableDubboConfigBinding 注解,代码如下:

// EnableDubboConfigBinding.java

@Target({ElementType.TYPE, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Repeatable(EnableDubboConfigBindings.class)
@Import(DubboConfigBindingRegistrar.class)
public @interface EnableDubboConfigBinding {

    /**
     * The name prefix of the properties that are valid to bind to {@link AbstractConfig Dubbo Config}.
     *
     * 配置前缀
     *
     * @return the name prefix of the properties to bind
     */
    String prefix();

    /**
     * 配置类
     *
     * @return The binding type of {@link AbstractConfig Dubbo Config}.
     * @see AbstractConfig
     * @see ApplicationConfig
     * @see ModuleConfig
     * @see RegistryConfig
     */
    Class type();

    /**
     * 是否 multiple
     *
     * It indicates whether {@link #prefix()} binding to multiple Spring Beans.
     *
     * @return the default value is false
     */
    boolean multiple() default false;

}
  • 每个属性,看其上的代码注释。
    • @Import(DubboConfigBindingRegistrar.class) 注解,表明使用 DubboConfigBindingRegistrar 类进行导入。详细的,我们继续来看 「4.4.1 DubboConfigBindingRegistrar」 。

4.4.1 DubboConfigBindingRegistrar

org.apache.dubbo.config.spring.context.annotation.DubboConfigBindingRegistrar ,实现 ImportBeanDefinitionRegistrar、EnvironmentAware 接口,处理 @EnableDubboConfigBinding 注解,注册相应的 Dubbo AbstractConfig 到 Spring 容器中。

4.4.1.1 registerBeanDefinitions

实现 #registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) 方法,处理 @EnableDubboConfigBinding 注解,注册相应的 Dubbo AbstractConfig 到 Spring 容器中。代码如下:

// DubboConfigBindingRegistrar.java

@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
    // <1> 获得 @EnableDubboConfigBinding 注解
    AnnotationAttributes attributes = AnnotationAttributes.fromMap(importingClassMetadata.getAnnotationAttributes(EnableDubboConfigBinding.class.getName()));
    // <2> 注册配置对应的 Bean Definition 对象
    registerBeanDefinitions(attributes, registry);
}

protected void registerBeanDefinitions(AnnotationAttributes attributes, BeanDefinitionRegistry registry) {
    // <2.1> 获得 prefix 属性
    String prefix = environment.resolvePlaceholders(attributes.getString("prefix")); // 因为,有可能有占位符,所以要解析。
    // <2.2> 获得 type 属性,即 AbstractConfig 的实现类
    Class configClass = attributes.getClass("type");
    // <2.3> 获得 multiple 属性
    boolean multiple = attributes.getBoolean("multiple");
    // <2.4> 注册 Dubbo Config Bean 对象
    registerDubboConfigBeans(prefix, configClass, multiple, registry);
}
  • <1> 处,获得 @EnableDubboConfigBinding 注解。
  • <2> 注册配置对应的 Bean Definition 对象。 这里有个知识点要补充下,Spring 在创建 Bean 之前,会将 XML 配置或者注解配置,先解析成对应的 BeanDefinition 对象,然后在创建 Bean 对象。
    • <2.1> 处,获得 prefix 属性。
    • <2.2> 处,获得 type 属性,即 AbstractConfig 的实现类。
    • <2.3> 处,获得 multiple 属性。
    • <2.4> 处,调用 #registerDubboConfigBeans(String prefix, Class configClass, boolean multiple, BeanDefinitionRegistry registry) 方法,注册 Dubbo Config Bean 对象。

4.4.1.2 registerDubboConfigBeans

#registerDubboConfigBeans(String prefix, Class configClass, boolean multiple, BeanDefinitionRegistry registry) 方法,注册 Dubbo Config Bean 对象。代码如下:

// DubboConfigBindingRegistrar.java

private void registerDubboConfigBeans(String prefix, Class configClass, boolean multiple,
                                      BeanDefinitionRegistry registry) {
    // <1.1> 获得 prefix 开头的配置属性
    Map properties = PropertySourcesUtils.getSubProperties(environment.getPropertySources(), prefix);
    // <1.2> 如果配置属性为空,则无需创建
    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;
    }
    // <2> 获得配置属性对应的 Bean 名字的集合
    Set beanNames = multiple ? resolveMultipleBeanNames(properties) :
            Collections.singleton(resolveSingleBeanName(properties, configClass, registry));
    // <3> 遍历 beanNames 数组,逐个注册
    for (String beanName : beanNames) {
        // <3.1> 注注册 Dubbo Config Bean 对象
        registerDubboConfigBean(beanName, configClass, registry);
        // <3.2> 注注册 Dubbo Config 对象对应的 DubboConfigBindingBeanPostProcessor 对象
        registerDubboConfigBindingBeanPostProcessor(prefix, beanName, multiple, registry);
    }
}
  • <1.1> 处,调用 PropertySourcesUtils#getSubProperties(Iterable> propertySources, String prefix)方法,获得 prefix 开头的配置属性。因为,后续会用这个属性,设置到创建的 Bean 对象中。
  • <1.2> 处,如果配置属性为空,则无需创建。
  • <2> 处,根据 multiple 的值,调用不同的方法,获得配置属性对应的 Bean 名字的集合。代码如下:

    // DubboConfigBindingRegistrar.java
    
    // 例如:dubbo.application.${beanName}.name=dubbo-demo-annotation-provider
    private Set resolveMultipleBeanNames(Map properties) {
        Set beanNames = new LinkedHashSet();
        for (String propertyName : properties.keySet()) {
            // 获取上述示例的 ${beanName} 字符串
            int index = propertyName.indexOf(".");
            if (index > 0) {
                String beanName = propertyName.substring(0, index);
                beanNames.add(beanName);
            }
        }
        return beanNames;
    }
    
    // 例如:dubbo.application.name=dubbo-demo-annotation-provider
    private String resolveSingleBeanName(Map properties, Class configClass,
                                         BeanDefinitionRegistry registry) {
        // 获得 Bean 的名字
        String beanName = (String) properties.get("id");
        // 如果定义,基于 Spring 提供的机制,生成对应的 Bean 的名字。例如说:org.apache.dubbo.config.ApplicationConfig#0
        if (!StringUtils.hasText(beanName)) {
            BeanDefinitionBuilder builder = BeanDefinitionBuilder.rootBeanDefinition(configClass);
            beanName = BeanDefinitionReaderUtils.generateBeanName(builder.getRawBeanDefinition(), registry);
        }
        return beanName;
    }
    
    • 这两个方法,看看我提供的示例。
    • #resolveMultipleBeanNames(Map properties) 方法,可能比较难理解一点。胖友可以增加如下到配置文件中:

      # application.properties
      dubbo.applications.x.name=biu
      dubbo.applications.y.name=biubiubiu
      
      • 此时,你需要指定 @Service Bean 使用哪个应用。
  • <3> 处,遍历 beanNames 数组,逐个注册。

    • <3.1> 处,调用 #registerDubboConfigBean(String beanName, Class configClass, BeanDefinitionRegistry registry) 方法,注册 Dubbo Config Bean 对象。代码如下:

      // DubboConfigBindingRegistrar.java
      
      private void registerDubboConfigBean(String beanName, Class configClass,
                                           BeanDefinitionRegistry registry) {
          // 创建 BeanDefinitionBuilder 对象
          BeanDefinitionBuilder builder = BeanDefinitionBuilder.rootBeanDefinition(configClass);
          // 获得 AbstractBeanDefinition 对象
          AbstractBeanDefinition beanDefinition = builder.getBeanDefinition();
          // 注册到 registry 中
          registry.registerBeanDefinition(beanName, beanDefinition);
          if (log.isInfoEnabled()) {
              log.info("The dubbo config bean definition [name : " + beanName + ", class : " + configClass.getName() + "] has been registered.");
          }
      }
      
      • 此时,仅仅是通过酱紫的方式,创建了一个 Dubbo Config Bean 对象,并没有将配置属性,设置到该对象中。答案在 <3.2> 中。
    • <3.2> 处,调用 #registerDubboConfigBindingBeanPostProcessor(String prefix, String beanName, boolean multiple, BeanDefinitionRegistry registry) 方法,注册 Dubbo Config 对象对象的 DubboConfigBindingBeanPostProcessor 对象。代码如下:

      // DubboConfigBindingRegistrar.java
      
      private void registerDubboConfigBindingBeanPostProcessor(String prefix, String beanName, boolean multiple,
                                                               BeanDefinitionRegistry registry) {
          // 创建 BeanDefinitionBuilder 对象
          Class processorClass = DubboConfigBindingBeanPostProcessor.class;
          BeanDefinitionBuilder builder = rootBeanDefinition(processorClass);
          // 添加构造方法的参数为 actualPrefix 和 beanName 。即,创建 DubboConfigBindingBeanPostProcessor 对象,需要这两个构造参数
          String actualPrefix = multiple ? PropertySourcesUtils.normalizePrefix(prefix) + beanName : prefix;
          builder.addConstructorArgValue(actualPrefix).addConstructorArgValue(beanName);
          // 获得 AbstractBeanDefinition 对象
          AbstractBeanDefinition beanDefinition = builder.getBeanDefinition();
          // 设置 role 属性
          beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
          // 注册到 registry 中
          BeanDefinitionReaderUtils.registerWithGeneratedName(beanDefinition, registry);
          if (log.isInfoEnabled()) {
              log.info("The BeanPostProcessor bean definition [" + processorClass.getName() + "] for dubbo config bean [name : " + beanName + "] has been registered.");
          }
      }
      
      • 因为此时 Dubbo Config Bean 对象还未创建,所以需要等后续它真的创建之后,使用 DubboConfigBindingBeanPostProcessor 类,实现对对象(Bean 对象)的配置输入的设置。

至此,我们发现,需要继续挖掘,让我们继续来看 「DubboConfigBindingBeanPostProcessor」 类。

4.5 DubboConfigBindingBeanPostProcessor

org.apache.dubbo.config.spring.beans.factory.annotation.DubboConfigBindingBeanPostProcessor ,实现 BeanPostProcessor、ApplicationContextAware、InitializingBean 接口,处理 Dubbo AbstractConfig Bean 的配置属性注入。

4.5.1 构造方法

// DubboConfigBindingBeanPostProcessor.java

/**
 * The prefix of Configuration Properties
 *
 * 配置属性的前缀
 */
private final String prefix;

/**
 * Binding Bean Name
 *
 * Bean 的名字
 */
private final String beanName;

private DubboConfigBinder dubboConfigBinder;

private ApplicationContext applicationContext;

/**
 * 是否忽略位置的属性
 */
private boolean ignoreUnknownFields = true;

/**
 * 是否忽略类型不对的属性
 */
private boolean ignoreInvalidFields = true;

/**
 * @param prefix   the prefix of Configuration Properties
 * @param beanName the binding Bean Name
 */
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;
}
  • 所以,我们在上文中会看到,创建 DubboConfigBindingBeanPostProcessor Bean 时,会有 builder.addConstructorArgValue(actualPrefix).addConstructorArgValue(beanName); 一段的代码。

4.5.2 afterPropertiesSet

#afterPropertiesSet() 方法,设置 dubboConfigBinder 属性。代码如下:

// DubboConfigBindingBeanPostProcessor.java

@Override
public void afterPropertiesSet() throws Exception {
    // 获得(创建)DubboConfigBinder 对象
    if (dubboConfigBinder == null) {
        try {
            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());
        }
    }
    // 设置 ignoreUnknownFields、ignoreInvalidFields 属性
    dubboConfigBinder.setIgnoreUnknownFields(ignoreUnknownFields);
    dubboConfigBinder.setIgnoreInvalidFields(ignoreInvalidFields);
}

/**
 * Create {@link DubboConfigBinder} instance.
 *
 * @param environment
 * @return {@link DefaultDubboConfigBinder}
 */
protected DubboConfigBinder createDubboConfigBinder(Environment environment) {
    // 创建 DefaultDubboConfigBinder 对象
    DefaultDubboConfigBinder defaultDubboConfigBinder = new DefaultDubboConfigBinder();
    // 设置 environment 属性
    defaultDubboConfigBinder.setEnvironment(environment);
    return defaultDubboConfigBinder;
}
  • 关于 DefaultDubboConfigBinder 类,我们在下面的小节先来瞅瞅。

4.5.2.1 DubboConfigBinder

org.apache.dubbo.config.spring.context.properties.DubboConfigBinder ,继承 EnvironmentAware 接口,Dubbo Config Binder 接口。代码如下:

// DubboConfigBinder.java

/**
 * {@link AbstractConfig DubboConfig} Binder
 *
 * @see AbstractConfig
 * @see EnvironmentAware
 * @since 2.5.11
 */
public interface DubboConfigBinder extends EnvironmentAware {

    /**
     * Set whether to ignore unknown fields, that is, whether to ignore bind
     * parameters that do not have corresponding fields in the target object.
     * 

Default is "true". Turn this off to enforce that all bind parameters * must have a matching field in the target object. * * @see #bind */ void setIgnoreUnknownFields(boolean ignoreUnknownFields); /** * Set whether to ignore invalid fields, that is, whether to ignore bind * parameters that have corresponding fields in the target object which are * not accessible (for example because of null values in the nested path). *

Default is "false". * * @see #bind */ void setIgnoreInvalidFields(boolean ignoreInvalidFields); /** * Bind the properties to Dubbo Config Object under specified prefix. * * @param prefix * @param dubboConfig */ void bind(String prefix, C dubboConfig); }

  • 后续的实现,我们会看到基于 Spring DataBinder 来实现。不了解 DataBinder 的胖友,可以看看 《Spring 验证、数据绑定和类型转换》 文章。

4.5.2.2 DubboConfigBinder

org.apache.dubbo.config.spring.context.properties.AbstractDubboConfigBinder ,实现 DubboConfigBinder 接口,DubboConfigBinder 的抽象基类。代码如下:

// AbstractDubboConfigBinder.java

public abstract class AbstractDubboConfigBinder implements DubboConfigBinder {

    /**
     * PropertySource 数组(迭代)
     */
    private Iterable> propertySources;

    private boolean ignoreUnknownFields = true;

    private boolean ignoreInvalidFields = false;

    /**
     * Get multiple {@link PropertySource propertySources}
     *
     * @return multiple {@link PropertySource propertySources}
     */
    protected Iterable> getPropertySources() {
        return propertySources;
    }

    public boolean isIgnoreUnknownFields() {
        return ignoreUnknownFields;
    }

    @Override
    public void setIgnoreUnknownFields(boolean ignoreUnknownFields) {
        this.ignoreUnknownFields = ignoreUnknownFields;
    }

    public boolean isIgnoreInvalidFields() {
        return ignoreInvalidFields;
    }

    @Override
    public void setIgnoreInvalidFields(boolean ignoreInvalidFields) {
        this.ignoreInvalidFields = ignoreInvalidFields;
    }

    @Override
    public final void setEnvironment(Environment environment) {
        if (environment instanceof ConfigurableEnvironment) {
            this.propertySources = ((ConfigurableEnvironment) environment).getPropertySources();
        }
    }

}
  • 提供默认的属性。

4.5.2.3 DefaultDubboConfigBinder

org.apache.dubbo.config.spring.context.properties.DefaultDubboConfigBinder ,继承 AbstractDubboConfigBinder 抽象类,使用 Spring DataBinder ,将配置属性设置到 Dubbo Config 对象中。代码如下:

// DefaultDubboConfigBinder.java

/**
 * Default {@link DubboConfigBinder} implementation based on Spring {@link DataBinder}
 */
public class DefaultDubboConfigBinder extends AbstractDubboConfigBinder {

    @Override
    public  void bind(String prefix, C dubboConfig) {
        // 将 dubboConfig 包装成 DataBinder 对象
        DataBinder dataBinder = new DataBinder(dubboConfig);
        // Set ignored*
        // 设置响应的 ignored* 属性
        dataBinder.setIgnoreInvalidFields(isIgnoreInvalidFields());
        dataBinder.setIgnoreUnknownFields(isIgnoreUnknownFields());
        // Get properties under specified prefix from PropertySources
        // 获得 prefix 开头的配置属性
        Map properties = PropertySourcesUtils.getSubProperties(getPropertySources(), prefix);
        // Convert Map to MutablePropertyValues
        // 创建 MutablePropertyValues 对象
        MutablePropertyValues propertyValues = new MutablePropertyValues(properties);
        // Bind
        // 绑定配置属性到 dubboConfig 中
        dataBinder.bind(propertyValues);
    }

}
  • 比较简单,胖友自己瞅一眼代码即可。

在 《Dubbo 源码分析 —— 集成 Spring Boot》 中,我们可以看到另外一个 AbstractDubboConfigBinder 的实现类 RelaxedDubboConfigBinder ,它是基于 Spring Boot Binder 进行实现。 因为艿艿没有深入了解过 Spring Boot Binder 相关,所以还说不出和 Spring DataBinder 的区别在哪。orz

4.5.3 postProcessBeforeInitialization

实现 #postProcessBeforeInitialization(Object bean, String beanName) 方法,设置配置属性到 Dubbo Config 中。代码如下:

// DubboConfigBindingBeanPostProcessor.java

@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
    // 判断必须是 beanName ,并且是 AbstractConfig 类型
    if (beanName.equals(this.beanName) && bean instanceof AbstractConfig) {
        AbstractConfig dubboConfig = (AbstractConfig) bean;
        // 设置属性到 dubboConfig 中
        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;
}

至此,Dubbo Config 对象的创建和属性设置,已经完成。如果胖友还是有点懵逼,可以调试一次,没有什么复杂逻辑哟。

5. @DubboComponentScan

org.apache.dubbo.config.spring.context.annotation.@DubboComponentScan 注解,配置要扫描 @Service 和 @Reference 注解的包或者类们,从而创建对应的 Bean 对象。代码如下:

// DubboComponentScan.java

/**
 * Dubbo Component Scan {@link Annotation},scans the classpath for annotated components that will be auto-registered as
 * Spring beans. Dubbo-provided {@link Service} and {@link Reference}.
 *
 * @see Service
 * @see Reference
 * @since 2.5.7
 */
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(DubboComponentScanRegistrar.class)
public @interface DubboComponentScan {

    /**
     * 和 {@link #basePackages()} 等价
     *
     * 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.
     * 

* 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 {}; }

  • @Import(DubboComponentScanRegistrar.class) 注解,表明使用 DubboComponentScanRegistrar 类进行导入。详细的,我们继续来看 「5.1 DubboComponentScanRegistrar」 。

5.1 DubboComponentScanRegistrar

org.apache.dubbo.config.spring.context.annotation.DubboComponentScanRegistrar ,实现 ImportBeanDefinitionRegistrar 接口,处理 @DubboComponentScan 注解,注册相应的 ServiceAnnotationBeanPostProcessor 和 ReferenceAnnotationBeanPostProcessor 到 Spring 容器中。代码如下:

// DubboComponentScanRegistrar.java

@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
    // <1> 获得要扫描的包
    Set packagesToScan = getPackagesToScan(importingClassMetadata);
    // <2> 创建 ServiceAnnotationBeanPostProcessor Bean 对象,后续扫描 `@Service` 注解的类,创建对应的 Service Bean 对象
    registerServiceAnnotationBeanPostProcessor(packagesToScan, registry);
    // <3> 创建 ReferenceAnnotationBeanPostProcessor Bean 对象,后续扫描 `@Reference` 注解的类,创建对应的 Reference Bean 对象
    registerReferenceAnnotationBeanPostProcessor(registry);
}

// ... 省略稍后调用的方法。
  • <1> 处,调用 #getPackagesToScan(AnnotationMetadata metadata) 方法,获得要扫描的包。代码如下:

    // DubboComponentScanRegistrar.java
    
    private Set getPackagesToScan(AnnotationMetadata metadata) {
        // 获得 @DubboComponentScan 注解
        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
        // 情况一,将属性添加到 packagesToScan 集合中
        Set packagesToScan = new LinkedHashSet(Arrays.asList(value));
        packagesToScan.addAll(Arrays.asList(basePackages));
        for (Class basePackageClass : basePackageClasses) {
            packagesToScan.add(ClassUtils.getPackageName(basePackageClass));
        }
        // 情况二,如果 packagesToScan 为空,则默认使用注解类所在的包
        if (packagesToScan.isEmpty()) {
            return Collections.singleton(ClassUtils.getPackageName(metadata.getClassName()));
        }
        return packagesToScan;
    }
    
    • 有两种情况,胖友看的时候,要注意下。
  • <2> 处,调用 #registerServiceAnnotationBeanPostProcessor(Set packagesToScan, BeanDefinitionRegistry registry) 方法,创建 ServiceAnnotationBeanPostProcessor Bean 对象,后续扫描 @Service 注解的类,创建对应的 Service Bean 对象。代码如下:

    // DubboComponentScanRegistrar.java
    
    private void registerServiceAnnotationBeanPostProcessor(Set packagesToScan, BeanDefinitionRegistry registry) {
        // 创建 BeanDefinitionBuilder 对象
        BeanDefinitionBuilder builder = BeanDefinitionBuilder.rootBeanDefinition(ServiceAnnotationBeanPostProcessor.class);
        // 设置构造方法参数为 packagesToScan ,即 BeanDefinitionBuilder 扫描该包
        builder.addConstructorArgValue(packagesToScan);
        // 设置 role 属性
        builder.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
        // 获得 AbstractBeanDefinition 对象
        AbstractBeanDefinition beanDefinition = builder.getBeanDefinition();
        // 注册到 registry 中
        BeanDefinitionReaderUtils.registerWithGeneratedName(beanDefinition, registry);
    }
    
    • 关于 ServiceAnnotationBeanPostProcessor 类,我们在 「5.2 ServiceAnnotationBeanPostProcessor」 中,详细解析。
  • <3> 处,调用 #registerReferenceAnnotationBeanPostProcessor(BeanDefinitionRegistry registry) 方法,创建 ReferenceAnnotationBeanPostProcessor Bean 对象,后续扫描 @Reference 注解的类,创建对应的 Reference Bean 对象。代码如下:

    // DubboComponentScanRegistrar.java
    
    private void registerReferenceAnnotationBeanPostProcessor(BeanDefinitionRegistry registry) {
        // Register @Reference Annotation Bean Processor
        BeanRegistrar.registerInfrastructureBean(registry, ReferenceAnnotationBeanPostProcessor.BEAN_NAME, ReferenceAnnotationBeanPostProcessor.class);
    }
    
    // BeanRegistrar.java
    
    public static void registerInfrastructureBean(BeanDefinitionRegistry beanDefinitionRegistry,
                                                  String beanName, Class beanType) {
        // 不存在 beanName 对应的 BeanDefinition 对象
        if (!beanDefinitionRegistry.containsBeanDefinition(beanName)) {
            // 创建 RootBeanDefinition 对象
            RootBeanDefinition beanDefinition = new RootBeanDefinition(beanType);
            // 设置 role
            beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
            // 注册到 beanDefinitionRegistry 中
            beanDefinitionRegistry.registerBeanDefinition(beanName, beanDefinition);
        }
    }
    
    • 关于 ReferenceAnnotationBeanPostProcessor 类,我们在 「5.3 ReferenceAnnotationBeanPostProcessor」 中,详细解析。

5.2 ServiceAnnotationBeanPostProcessor

org.apache.dubbo.config.spring.beans.factory.annotation.ServiceAnnotationBeanPostProcessor ,实现 BeanDefinitionRegistryPostProcessor、EnvironmentAware、ResourceLoaderAware、BeanClassLoaderAware 接口,扫描 @Service 注解的类,创建对应的 Spring BeanDefinition 对象,从而创建 Dubbo Service Bean 对象。

5.2.1 构造方法

// ServiceAnnotationBeanPostProcessor.java

/**
 * 要扫描的包的集合
 */
private final Set packagesToScan;

private Environment environment;

private ResourceLoader resourceLoader;

private ClassLoader classLoader;

public ServiceAnnotationBeanPostProcessor(String... packagesToScan) { // 上述文章使用到的构造方法
    this(Arrays.asList(packagesToScan));
}

public ServiceAnnotationBeanPostProcessor(Collection packagesToScan) {
    this(new LinkedHashSet(packagesToScan));
}

public ServiceAnnotationBeanPostProcessor(Set packagesToScan) {
    this.packagesToScan = packagesToScan;
}

5.2.2 postProcessBeanDefinitionRegistry

实现 #postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) 方法,扫描 @Service 注解的类,创建对应的 Spring BeanDefinition 对象,从而创建 Dubbo Service Bean 对象。代码如下:

// ServiceAnnotationBeanPostProcessor.java

@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
    // <1> 解析 packagesToScan 集合。因为,可能存在占位符
    Set resolvedPackagesToScan = resolvePackagesToScan(packagesToScan);
    // <2> 扫描 packagesToScan 包,创建对应的 Spring BeanDefinition 对象,从而创建 Dubbo Service Bean 对象。
    if (!CollectionUtils.isEmpty(resolvedPackagesToScan)) {
        registerServiceBeans(resolvedPackagesToScan, registry);
    } else {
        if (logger.isWarnEnabled()) {
            logger.warn("packagesToScan is empty , ServiceBean registry will be ignored!");
        }
    }
}
  • <1> 处,调用 #resolvePackagesToScan(Set packagesToScan) 方法,解析 packagesToScan 集合。因为,可能存在占位符。代码如下:

    // ServiceAnnotationBeanPostProcessor.java
    
    private Set resolvePackagesToScan(Set packagesToScan) {
        Set resolvedPackagesToScan = new LinkedHashSet(packagesToScan.size());
        // 遍历 packagesToScan 数组
        for (String packageToScan : packagesToScan) {
            if (StringUtils.hasText(packageToScan)) {
                // 解析可能存在的占位符
                String resolvedPackageToScan = environment.resolvePlaceholders(packageToScan.trim());
                // 添加到 resolvedPackagesToScan 中
                resolvedPackagesToScan.add(resolvedPackageToScan);
            }
        }
        return resolvedPackagesToScan;
    }
    
  • <2> 处,调用 #registerServiceBeans(Set packagesToScan, BeanDefinitionRegistry registry) 方法,扫描 packagesToScan 包,创建对应的 Spring BeanDefinition 对象,从而创建 Dubbo Service Bean 对象。详细解析,见 「5.2.3 resolvePackagesToScan」 中。

5.2.3 resolvePackagesToScan

#registerServiceBeans(Set packagesToScan, BeanDefinitionRegistry registry) 方法,扫描 packagesToScan 包,创建对应的 Spring BeanDefinition 对象,从而创建 Dubbo Service Bean 对象。代码如下:

// ServiceAnnotationBeanPostProcessor.java

private void registerServiceBeans(Set packagesToScan, BeanDefinitionRegistry registry) {
    // <1.1> 创建 DubboClassPathBeanDefinitionScanner 对象
    DubboClassPathBeanDefinitionScanner scanner = new DubboClassPathBeanDefinitionScanner(registry, environment, resourceLoader);
    // <1.2> 获得 BeanNameGenerator 对象,并设置 beanNameGenerator 到 scanner 中
    BeanNameGenerator beanNameGenerator = resolveBeanNameGenerator(registry);
    scanner.setBeanNameGenerator(beanNameGenerator);
    // <1.3> 设置过滤获得带有 @Service 注解的类
    scanner.addIncludeFilter(new AnnotationTypeFilter(Service.class));

    // <2> 遍历 packagesToScan 数组
    for (String packageToScan : packagesToScan) {
        // Registers @Service Bean first
        // <2.1> 执行扫描
        scanner.scan(packageToScan);
        // Finds all BeanDefinitionHolders of @Service whether @ComponentScan scans or not.
        // <2.2> 创建每个在 packageToScan 扫描到的类,对应的 BeanDefinitionHolder 对象,返回 BeanDefinitionHolder 集合
        Set beanDefinitionHolders = findServiceBeanDefinitionHolders(scanner, packageToScan, registry, beanNameGenerator);
        // <2.3> 注册到 registry 中
        if (!CollectionUtils.isEmpty(beanDefinitionHolders)) {
            for (BeanDefinitionHolder beanDefinitionHolder : beanDefinitionHolders) {
                registerServiceBean(beanDefinitionHolder, registry, scanner);
            }
            if (logger.isInfoEnabled()) {
                logger.info(beanDefinitionHolders.size() + " annotated Dubbo's @Service Components { " + beanDefinitionHolders + " } were scanned under package[" + packageToScan + "]");
            }
        } else {
            if (logger.isWarnEnabled()) {
                logger.warn("No Spring Bean annotating Dubbo's @Service was found under package[" + packageToScan + "]");
            }
        }
    }
}
  • <1.1> 处,创建 DubboClassPathBeanDefinitionScanner 对象。它是用于扫描指定包下符合条件的类,用于将每个符合条件的类,创建对应的 BeanDefinition 对象,从而创建 Bean 。关于 DubboClassPathBeanDefinitionScanner 类,胖友点击 链接 瞅一眼即可。
  • <1.2> 处,调用 #resolveBeanNameGenerator(BeanDefinitionRegistry registry) 方法,获得 BeanNameGenerator 对象,并设置 beanNameGenerator 到 scanner 中。代码如下:

    // ServiceAnnotationBeanPostProcessor.java
    
    /**
     * It'd better to use BeanNameGenerator instance that should reference
     * {@link ConfigurationClassPostProcessor#componentScanBeanNameGenerator},
     * thus it maybe a potential problem on bean name generation.
     *
     * @param registry {@link BeanDefinitionRegistry}
     * @return {@link BeanNameGenerator} instance
     * @see SingletonBeanRegistry
     * @see AnnotationConfigUtils#CONFIGURATION_BEAN_NAME_GENERATOR
     * @see ConfigurationClassPostProcessor#processConfigBeanDefinitions
     * @since 2.5.8
     */
    @SuppressWarnings("Duplicates")
    private BeanNameGenerator resolveBeanNameGenerator(BeanDefinitionRegistry registry) {
        BeanNameGenerator beanNameGenerator = null;
        // 如果是 SingletonBeanRegistry 类型,从中获得对应的 BeanNameGenerator Bean 对象
        if (registry instanceof SingletonBeanRegistry) {
            SingletonBeanRegistry singletonBeanRegistry = SingletonBeanRegistry.class.cast(registry);
            beanNameGenerator = (BeanNameGenerator) singletonBeanRegistry.getSingleton(AnnotationConfigUtils.CONFIGURATION_BEAN_NAME_GENERATOR);
        }
        // 如果不存在,则创建 AnnotationBeanNameGenerator 对象
        if (beanNameGenerator == null) {
            if (logger.isInfoEnabled()) {
                logger.info("BeanNameGenerator bean can't be found in BeanFactory with name [" + CONFIGURATION_BEAN_NAME_GENERATOR + "]");
                logger.info("BeanNameGenerator will be a instance of " + AnnotationBeanNameGenerator.class.getName() + " , it maybe a potential problem on bean name generation.");
            }
            beanNameGenerator = new AnnotationBeanNameGenerator();
        }
        return beanNameGenerator;
    }
    
  • <1.3> 处,设置过滤获得带有 @Service 注解的类。关于 @Service 注解的具体的属性,本文就不过分介绍,胖友自己瞅瞅。

  • <2> 处,遍历 packagesToScan 数组。
    • <2.1> 处,调用 DubboClassPathBeanDefinitionScanner#scan(String... basePackages) 方法,执行扫描。
    • <2.2> 处,调用 #findServiceBeanDefinitionHolders(ClassPathBeanDefinitionScanner scanner, String packageToScan, BeanDefinitionRegistry registry, BeanNameGenerator beanNameGenerator) 方法,创建每个在 packageToScan 扫描到的类,对应的 BeanDefinitionHolder 对象,返回 BeanDefinitionHolder 集合。详细解析 ,见 「5.2.4 findServiceBeanDefinitionHolders」 中。
    • <2.3> 处,调用 #registerServiceBean(BeanDefinitionHolder beanDefinitionHolder, BeanDefinitionRegistry registry, DubboClassPathBeanDefinitionScanner scanner) 方法,注册到 registry 中。详细解析,见 「5.2.5 registerServiceBean」 中。

5.2.4 findServiceBeanDefinitionHolders

#findServiceBeanDefinitionHolders(ClassPathBeanDefinitionScanner scanner, String packageToScan, BeanDefinitionRegistry registry, BeanNameGenerator beanNameGenerator) 方法,创建每个在 packageToScan 扫描到的类,对应的 BeanDefinitionHolder 对象,返回 BeanDefinitionHolder 集合。代码如下:

// ServiceAnnotationBeanPostProcessor.java

/**
 * Finds a {@link Set} of {@link BeanDefinitionHolder BeanDefinitionHolders} whose bean type annotated
 * {@link Service} Annotation.
 *
 * @param scanner       {@link ClassPathBeanDefinitionScanner}
 * @param packageToScan pachage to scan
 * @param registry      {@link BeanDefinitionRegistry}
 * @return non-null
 * @since 2.5.8
 */
@SuppressWarnings("Duplicates")
private Set findServiceBeanDefinitionHolders(
        ClassPathBeanDefinitionScanner scanner, String packageToScan, BeanDefinitionRegistry registry,
        BeanNameGenerator beanNameGenerator) {
    // 获得 packageToScan 包下符合条件的 BeanDefinition 集合
    Set beanDefinitions = scanner.findCandidateComponents(packageToScan);

    // 创建 BeanDefinitionHolder 集合
    Set beanDefinitionHolders = new LinkedHashSet(beanDefinitions.size());
    // 遍历 beanDefinitions 数组
    for (BeanDefinition beanDefinition : beanDefinitions) {
        // 获得 Bean 的名字
        String beanName = beanNameGenerator.generateBeanName(beanDefinition, registry);
        // 创建 BeanDefinitionHolder 对象
        BeanDefinitionHolder beanDefinitionHolder = new BeanDefinitionHolder(beanDefinition, beanName);
        // 添加到 beanDefinitions 中
        beanDefinitionHolders.add(beanDefinitionHolder);
    }
    return beanDefinitionHolders;
}

5.2.5 registerServiceBean

#registerServiceBean(BeanDefinitionHolder beanDefinitionHolder, BeanDefinitionRegistry registry, DubboClassPathBeanDefinitionScanner scanner) 方法,注册到 registry 中。代码如下:

// ServiceAnnotationBeanPostProcessor.java

/**
 * Registers {@link ServiceBean} from new annotated {@link Service} {@link BeanDefinition}
 *
 * @param beanDefinitionHolder
 * @param registry
 * @param scanner
 * @see ServiceBean
 * @see BeanDefinition
 */
@SuppressWarnings("Duplicates")
private void registerServiceBean(BeanDefinitionHolder beanDefinitionHolder, BeanDefinitionRegistry registry,
                                 DubboClassPathBeanDefinitionScanner scanner) {
    // <1.1> 解析 Bean 的类
    Class beanClass = resolveClass(beanDefinitionHolder);
    // <1.2> 获得 @Service 注解
    Service service = AnnotationUtils.findAnnotation(beanClass, Service.class);
    // <1.3> 获得 Service 接口
    Class interfaceClass = resolveServiceInterfaceClass(beanClass, service);
    // <1.4> 获得 Bean 的名字
    String annotatedServiceBeanName = beanDefinitionHolder.getBeanName();
    // <1.5> 创建 AbstractBeanDefinition 对象
    AbstractBeanDefinition serviceBeanDefinition = buildServiceBeanDefinition(service, interfaceClass, annotatedServiceBeanName);

    // ServiceBean Bean name
    // <2> 重新生成 Bean 的名字
    String beanName = generateServiceBeanName(service, interfaceClass, annotatedServiceBeanName);
    // <3> 校验在 scanner 中,已经存在 beanName 。若不存在,则进行注册。
    if (scanner.checkCandidate(beanName, serviceBeanDefinition)) { // check duplicated candidate bean
        registry.registerBeanDefinition(beanName, serviceBeanDefinition);
        if (logger.isInfoEnabled()) {
            logger.info("The BeanDefinition[" + serviceBeanDefinition + "] of ServiceBean has been registered with name : " + beanName);
        }
    } else {
        if (logger.isWarnEnabled()) {
            logger.warn("The Duplicated BeanDefinition[" + serviceBeanDefinition + "] of ServiceBean[ bean name : " + beanName + "] was be found , Did @DubboComponentScan scan to same package in many times?");
        }
    }
}
  • <1.1> 处,调用 #resolveClass(BeanDefinitionHolder beanDefinitionHolder) 方法,解析返回 Bean 的类。代码如下:

    // ServiceAnnotationBeanPostProcessor.java
    
    private Class resolveClass(BeanDefinitionHolder beanDefinitionHolder) {
        BeanDefinition beanDefinition = beanDefinitionHolder.getBeanDefinition();
        return resolveClass(beanDefinition);
    }
    
    private Class resolveClass(BeanDefinition beanDefinition) {
        String beanClassName = beanDefinition.getBeanClassName();
        return ClassUtils.resolveClassName(beanClassName, classLoader);
    }
    
    • 因为 BeanDefinition 的 beanClassName 是 String 类型,所以得转换成 Class 类型。
  • <1.2> 处,获得 @Service 注解。

  • <1.3> 处,调用 #resolveServiceInterfaceClass(Class annotatedServiceBeanClass, Service service) 方法,获得 Service 接口。代码如下:

    // ServiceAnnotationBeanPostProcessor.java
    
    @SuppressWarnings("Duplicates")
    private Class resolveServiceInterfaceClass(Class annotatedServiceBeanClass, Service service) {
        // 首先,从注解本身上获得
        Class interfaceClass = service.interfaceClass();
        if (void.class.equals(interfaceClass)) { // 一般是满足的
            interfaceClass = null;
            // 获得 @Service 注解的 interfaceName 属性。
            String interfaceClassName = service.interfaceName();
            // 如果存在,获得其对应的类
            if (StringUtils.hasText(interfaceClassName)) {
                if (ClassUtils.isPresent(interfaceClassName, classLoader)) {
                    interfaceClass = ClassUtils.resolveClassName(interfaceClassName, classLoader);
                }
            }
        }
    
        // 【一般情况下,使用这个】获得不到,则从被注解的类上获得其实现的首个接口
        if (interfaceClass == null) {
            Class[] allInterfaces = annotatedServiceBeanClass.getInterfaces();
            if (allInterfaces.length > 0) {
                interfaceClass = allInterfaces[0];
            }
        }
    
        Assert.notNull(interfaceClass, "@Service interfaceClass() or interfaceName() or interface class must be present!");
        Assert.isTrue(interfaceClass.isInterface(), "The type that was annotated @Service is not an interface!");
        return interfaceClass;
    }
    
    • 虽然代码比较长,但是重点看  处,从被注解的类上获得其实现的首个接口。
  • <1.4> 处,获得 Bean 的名字。

  • <1.5> 处,调用 #buildServiceBeanDefinition(Service service, Class interfaceClass, String annotatedServiceBeanName) 方法,创建 AbstractBeanDefinition 对象。代码如下:

    // ServiceAnnotationBeanPostProcessor.java
    
    @SuppressWarnings("Duplicates")
    private AbstractBeanDefinition buildServiceBeanDefinition(Service service, Class interfaceClass, String annotatedServiceBeanName) {
        // 创建 BeanDefinitionBuilder 对象
        BeanDefinitionBuilder builder = BeanDefinitionBuilder.rootBeanDefinition(ServiceBean.class);
        // 获得 AbstractBeanDefinition 对象
        AbstractBeanDefinition beanDefinition = builder.getBeanDefinition();
    
        // 获得 MutablePropertyValues 属性。后续 ,通过向它添加属性,设置到 BeanDefinition 中,即 Service Bean 中。
        MutablePropertyValues propertyValues = beanDefinition.getPropertyValues();
    
        //  创建 AnnotationPropertyValuesAdapter 对象,添加到 propertyValues 中。
        // 此处,是将注解上的属性,设置到 propertyValues 中
        String[] ignoreAttributeNames = of("provider", "monitor", "application", "module", "registry", "protocol", "interface", "interfaceName"); // 忽略的属性,下面进行单独设置。
        propertyValues.addPropertyValues(new AnnotationPropertyValuesAdapter(service, environment, ignoreAttributeNames));
    
        // References "ref" property to annotated-@Service Bean
        // 设置 ref 属性指向的 Service Bean 名字
        addPropertyReference(builder, "ref", annotatedServiceBeanName);
        // Set interface 设置 Service 接口类全类名
        builder.addPropertyValue("interface", interfaceClass.getName());
    
        /**
         * Add {@link org.apache.dubbo.config.ProviderConfig} Bean reference
         *
         * 添加 provider 属性对应的 ProviderConfig Bean 对象
         */
        String providerConfigBeanName = service.provider();
        if (StringUtils.hasText(providerConfigBeanName)) {
            addPropertyReference(builder, "provider", providerConfigBeanName);
        }
    
        /**
         * Add {@link org.apache.dubbo.config.MonitorConfig} Bean reference
         *
         * 添加 monitor 属性对应的 MonitorConfig Bean 对象
         */
        String monitorConfigBeanName = service.monitor();
        if (StringUtils.hasText(monitorConfigBeanName)) {
            addPropertyReference(builder, "monitor", monitorConfigBeanName);
        }
    
        /**
         * Add {@link org.apache.dubbo.config.ApplicationConfig} Bean reference
         *
         * 添加 application 属性对应的 ApplicationConfig Bean 对象
         */
        String applicationConfigBeanName = service.application();
        if (StringUtils.hasText(applicationConfigBeanName)) {
            addPropertyReference(builder, "application", applicationConfigBeanName);
        }
    
        /**
         * Add {@link org.apache.dubbo.config.ModuleConfig} Bean reference
         *
         * 添加 module 属性对应的 ModuleConfig Bean 对象
         */
        String moduleConfigBeanName = service.module();
        if (StringUtils.hasText(moduleConfigBeanName)) {
            addPropertyReference(builder, "module", moduleConfigBeanName);
        }
    
    
        /**
         * Add {@link org.apache.dubbo.config.RegistryConfig} Bean reference
         *
         * 添加 registries 属性对应的 RegistryConfig Bean 数组(一个或多个)
         */
        String[] registryConfigBeanNames = service.registry();
        List registryRuntimeBeanReferences = toRuntimeBeanReferences(registryConfigBeanNames);
        if (!registryRuntimeBeanReferences.isEmpty()) {
            builder.addPropertyValue("registries", registryRuntimeBeanReferences);
        }
    
        /**
         * Add {@link org.apache.dubbo.config.ProtocolConfig} Bean reference
         *
         * 添加 protocols 属性对应的 ProtocolConfig Bean 数组(一个或多个)
         */
        String[] protocolConfigBeanNames = service.protocol();
        List protocolRuntimeBeanReferences = toRuntimeBeanReferences(protocolConfigBeanNames);
        if (!protocolRuntimeBeanReferences.isEmpty()) {
            builder.addPropertyValue("protocols", protocolRuntimeBeanReferences);
        }
    
        return builder.getBeanDefinition();
    }
    
    // RuntimeBeanReference ,在解析到依赖的Bean的时侯,解析器会依据依赖bean的name创建一个RuntimeBeanReference对像,将这个对像放入BeanDefinition的MutablePropertyValues中。
    // 此处,和上面不太一样的原因,因为是多个
    @SuppressWarnings("Duplicates")
    private ManagedList toRuntimeBeanReferences(String... beanNames) {
        ManagedList runtimeBeanReferences = new ManagedList();
        if (!ObjectUtils.isEmpty(beanNames)) {
            for (String beanName : beanNames) {
                // 解析真正的 Bean 名字,如果有占位符的话
                String resolvedBeanName = environment.resolvePlaceholders(beanName);
                runtimeBeanReferences.add(new RuntimeBeanReference(resolvedBeanName));
            }
        }
        return runtimeBeanReferences;
    }
    
    // 添加属性值是引用类型
    private void addPropertyReference(BeanDefinitionBuilder builder, String propertyName, String beanName) {
        String resolvedBeanName = environment.resolvePlaceholders(beanName);
        builder.addPropertyReference(propertyName, resolvedBeanName);
    }
    
    • 比较冗长,顺着往下看即可。
    •  处,创建 AnnotationPropertyValuesAdapter 对象,添加到 propertyValues 中。此处,是将注解上的属性,设置到 propertyValues 中。也就是说,注解上的属性,自然的能够设置到后续创建的 Service Bean 的对象中。
      • 举个例子,如果说 @Service(version="1.0.0") ,那么这个版本号(version),就可以设置到 Dubbo Service Bean 中去了。
      • 关于 org.apache.dubbo.config.spring.beans.factory.annotation.AnnotationPropertyValuesAdapter 类,就是上述的用途,比较简单,胖友点击 链接 查看即可。
  • <2> 处,调用 #generateServiceBeanName(Service service, Class interfaceClass, String annotatedServiceBeanName)方法,重新生成 Bean 的名字。代码如下:

    // ServiceAnnotationBeanPostProcessor.java
    
    private String generateServiceBeanName(Service service, Class interfaceClass, String annotatedServiceBeanName) {
        ServiceBeanNameBuilder builder = ServiceBeanNameBuilder.create(service, interfaceClass, environment);
        return builder.build();
    }
    
    // ServiceBeanNameBuilder.java
    
    private static final String SEPARATOR = ":";
    
    private final String interfaceClassName;
    private final Environment environment;
    // Optional
    private String version;
    private String group;
    
    // ServiceBean:${interfaceClassName}:${version}:${group}
    public String build() {
        StringBuilder beanNameBuilder = new StringBuilder("ServiceBean");
        // Required
        append(beanNameBuilder, interfaceClassName);
        // Optional
        append(beanNameBuilder, version);
        append(beanNameBuilder, group);
        // Build
        String rawBeanName = beanNameBuilder.toString();
        // Resolve placeholders
        return environment.resolvePlaceholders(rawBeanName);
    }
    
    private static void append(StringBuilder builder, String value) {
        if (StringUtils.hasText(value)) {
            builder.append(SEPARATOR).append(value);
        }
    }
    
    • 结果示例如下:Dubbo(九):注解配置_第2张图片
  • <3> 处,校验在 scanner 中,是否已经存在 beanName 。若不存在,则进行注册。

整个逻辑,有点长长滴。胖友辛苦上下滑动,在瞅瞅。

5.3 ReferenceAnnotationBeanPostProcessor

org.apache.dubbo.config.spring.beans.factory.annotation.ReferenceAnnotationBeanPostProcessor ,继承 AnnotationInjectedBeanPostProcessor 抽象类,实现 ApplicationContextAware、ApplicationListener 接口,扫描 @Reference 注解的类,创建对应的 Spring BeanDefinition 对象,从而创建 Dubbo Reference Bean 对象。

虽然 org.apache.dubbo.config.spring.beans.factory.annotation.AnnotationInjectedBeanPostProcessor 放在 Dubbo 项目中,但是是 clone 自 https://github.com/alibaba/spring-context-support/blob/1.0.2/src/main/java/com/alibaba/spring/beans/factory/annotation/AnnotationInjectedBeanPostProcessor.java类。所以呢,我们先不深究这个类,只要知道如下:

  • 英文:Abstract generic {@link BeanPostProcessor} implementation for customized annotation that annotated injected-object.
  • 中文:BeanPostProcessor 的抽象实现类,用于支持使用自定义注解,注入对象的属性。
  • 此时,ReferenceAnnotationBeanPostProcessor 实现的就是 支持 @Reference 注解的属性注入。

相对来说,本节的 ReferenceAnnotationBeanPostProcessor ,会比上一节的 ServiceAnnotationBeanPostProcessor 复杂蛮多~ SO ,保持耐心哈。

5.3.1 构造方法

// ReferenceAnnotationBeanPostProcessor.java

/**
 * The bean name of {@link ReferenceAnnotationBeanPostProcessor}
 */
public static final String BEAN_NAME = "referenceAnnotationBeanPostProcessor";

/**
 * Cache size
 */
private static final int CACHE_SIZE = Integer.getInteger(BEAN_NAME + ".cache.size", 32);

/**
 * ReferenceBean 缓存 Map
 *
 * KEY:Reference Bean 的名字
 */
private final ConcurrentMap> referenceBeanCache = new ConcurrentHashMap>(CACHE_SIZE);

/**
 * ReferenceBeanInvocationHandler 缓存 Map
 *
 * KEY:Reference Bean 的名字
 */
private final ConcurrentHashMap localReferenceBeanInvocationHandlerCache = new ConcurrentHashMap(CACHE_SIZE);

/**
 * 使用属性进行注入的 @Reference Bean 的缓存 Map
 *
 * 一般情况下,使用这个
 */
private final ConcurrentMap> injectedFieldReferenceBeanCache = new ConcurrentHashMap>(CACHE_SIZE);

/**
 * 使用方法进行注入的 @Reference Bean 的缓存 Map
 */
private final ConcurrentMap> injectedMethodReferenceBeanCache = new ConcurrentHashMap>(CACHE_SIZE);

private ApplicationContext applicationContext;
  • 具体的每个变量的时候,结合下面来看。

5.3.2 doGetInjectedBean

实现 #doGetInjectedBean(Reference reference, Object bean, String beanName, Class injectedType, InjectionMetadata.InjectedElement injectedElement) 方法,获得要注入的 @Reference Bean 。代码如下:

// ReferenceAnnotationBeanPostProcessor.java

@Override
protected Object doGetInjectedBean(Reference reference, Object bean, String beanName, Class injectedType,
                                   InjectionMetadata.InjectedElement injectedElement) throws Exception {
    // <1> 获得 Reference Bean 的名字
    String referencedBeanName = buildReferencedBeanName(reference, injectedType);
    // <2> 创建 ReferenceBean 对象
    ReferenceBean referenceBean = buildReferenceBeanIfAbsent(referencedBeanName, reference, injectedType, getClassLoader());
    // <3> 缓存到 injectedFieldReferenceBeanCache or injectedMethodReferenceBeanCache 中
    cacheInjectedReferenceBean(referenceBean, injectedElement);
    // <4> 创建 Proxy 代理对象
    return buildProxy(referencedBeanName, referenceBean, injectedType);
}
  • <1> 处,调用 #buildReferencedBeanName(Reference reference, Class injectedType) 方法,获得 Reference Bean 的名字。代码如下:

    // ReferenceAnnotationBeanPostProcessor.java
    
    private String buildReferencedBeanName(Reference reference, Class injectedType) {
        // 创建 Service Bean 的名字
        ServiceBeanNameBuilder builder = ServiceBeanNameBuilder.create(reference, injectedType, getEnvironment());
        return getEnvironment().resolvePlaceholders(builder.build()); // 这里,貌似重复解析占位符了。不过没啥影响~
    }
    
    • 实际上,使用的就是 ServiceBeanNameBuilder 的逻辑,即和 Dubbo Service Bean 的名字,是 同一套。当然,这个也非常合理~
  • <2> 处,调用 #buildReferenceBeanIfAbsent(String referencedBeanName, Reference reference, Class referencedType, ClassLoader classLoader) 方法,创建(获得) ReferenceBean 对象。代码如下:

    // ReferenceAnnotationBeanPostProcessor.java
    
    private ReferenceBean buildReferenceBeanIfAbsent(String referencedBeanName, Reference reference, Class referencedType, ClassLoader classLoader)
            throws Exception {
        // 首先,从 referenceBeanCache 缓存中,获得 referencedBeanName 对应的 ReferenceBean 对象
        ReferenceBean referenceBean = referenceBeanCache.get(referencedBeanName);
        // 然后,如果不存在,则进行创建。然后,添加到 referenceBeanCache 缓存中。
        if (referenceBean == null) {
            ReferenceBeanBuilder beanBuilder = ReferenceBeanBuilder
                    .create(reference, classLoader, applicationContext)
                    .interfaceClass(referencedType);
            referenceBean = beanBuilder.build();
            referenceBeanCache.put(referencedBeanName, referenceBean);
        }
        return referenceBean;
    }
    
    • 其中,会使用 ReferenceBeanBuilder 类,构建 ReferenceBean 对象。关于它,我们稍后在 「5.3.4 ReferenceBeanBuilder」 来瞅瞅。实际上,和上面 ServiceBean 的构建,也差不了太多。
  • <3> 处,调用 #cacheInjectedReferenceBean(String referencedBeanName, Reference reference, Class referencedType, ClassLoader classLoader) 方法,缓存到 injectedFieldReferenceBeanCache or injectedMethodReferenceBeanCache 中。代码如下:

    // ReferenceAnnotationBeanPostProcessor.java
    
    private void cacheInjectedReferenceBean(ReferenceBean referenceBean, InjectionMetadata.InjectedElement injectedElement) {
        if (injectedElement.getMember() instanceof Field) {
            injectedFieldReferenceBeanCache.put(injectedElement, referenceBean);
        } else if (injectedElement.getMember() instanceof Method) {
            injectedMethodReferenceBeanCache.put(injectedElement, referenceBean);
        }
    }
    
  • <4> 处,调用 #buildProxy(String referencedBeanName, ReferenceBean referenceBean, Class injectedType) 方法,创建 Proxy 代理对象。代码如下:

    // ReferenceAnnotationBeanPostProcessor.java
    
    private Object buildProxy(String referencedBeanName, ReferenceBean referenceBean, Class injectedType) {
        InvocationHandler handler = buildInvocationHandler(referencedBeanName, referenceBean);
        return Proxy.newProxyInstance(getClassLoader(), new Class[]{injectedType}, handler);
    }
    
    private InvocationHandler buildInvocationHandler(String referencedBeanName, ReferenceBean referenceBean) {
        // 首先,从 localReferenceBeanInvocationHandlerCache 缓存中,获得 ReferenceBeanInvocationHandler 对象
        ReferenceBeanInvocationHandler handler = localReferenceBeanInvocationHandlerCache.get(referencedBeanName);
        // 然后,如果不存在,则创建 ReferenceBeanInvocationHandler 对象
        if (handler == null) {
            handler = new ReferenceBeanInvocationHandler(referenceBean);
        }
    
        //  之后,根据引用的 Dubbo 服务是远程的还是本地的,做不同的处理。
        // 【本地】判断如果 applicationContext 中已经初始化,说明是本地的 @Service Bean ,则添加到 localReferenceBeanInvocationHandlerCache 缓存中。
        // 等到本地的 @Service Bean 暴露后,再进行初始化。
        if (applicationContext.containsBean(referencedBeanName)) { // Is local @Service Bean or not ?
            // ReferenceBeanInvocationHandler's initialization has to wait for current local @Service Bean has been exported.
            localReferenceBeanInvocationHandlerCache.put(referencedBeanName, handler);
        // 【远程】判断若果 applicationContext 中未初始化,说明是远程的 @Service Bean 对象,则立即进行初始化
        } else {
            // Remote Reference Bean should initialize immediately
            handler.init();
        }
        return handler;
    }
    
    • 比较复杂的是, 处,根据引用的 Dubbo 服务是远程的还是本地的,做不同的处理。为什么呢?
      • 远程的 Dubbo 服务,理论来说(不考虑对方挂掉的情况),是已经存在,此时可以进行加载引用。
      • 本地的 Dubbo 服务,此时并未暴露,则先添加到 localReferenceBeanInvocationHandlerCache 中进行缓存。等后续的,通过 Spring 事件监听的功能,进行实现。详细的,我们在 「5.3.3 onApplicationEvent」 中会看到。
    • ReferenceBeanInvocationHandler ,是 ReferenceAnnotationBeanPostProcessor 的内部静态类,实现 Dubbo InvocationHandler 接口,代码如下:

      // ReferenceAnnotationBeanPostProcessor#ReferenceBeanInvocationHandler.java
      
      private static class ReferenceBeanInvocationHandler implements InvocationHandler {
      
          /**
           * ReferenceBean 对象
           */
          private final ReferenceBean referenceBean;
      
          /**
           * Bean 对象
           */
          private Object bean;
      
          private ReferenceBeanInvocationHandler(ReferenceBean referenceBean) {
              this.referenceBean = referenceBean;
          }
      
          @Override
          public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
              // 调用 bean 的对应的方法
              return method.invoke(bean, args);
          }
      
          // 通过初始化方法,可以获得 `ReferenceBean.ref`
          private void init() {
              this.bean = referenceBean.get();
          }
      
      }
      
      • 重心在于 #init() 方法,可以调用 ReferenceBean#get() 方法,进行引用的 Bean 的初始化,最后返回引用 ref 。

5.3.3 onApplicationEvent

实现 #onApplicationEvent(ApplicationEvent event) 方法,代码如下:

// ReferenceAnnotationBeanPostProcessor.java

@Override
public void onApplicationEvent(ApplicationEvent event) {
    if (event instanceof ServiceBeanExportedEvent) {
        onServiceBeanExportEvent((ServiceBeanExportedEvent) event);
    } else if (event instanceof ContextRefreshedEvent) {
        onContextRefreshedEvent((ContextRefreshedEvent) event);
    }
}

private void onServiceBeanExportEvent(ServiceBeanExportedEvent event) {
    // 获得 ServiceBean 对象
    ServiceBean serviceBean = event.getServiceBean();
    // 初始化对应的 ReferenceBeanInvocationHandler
    initReferenceBeanInvocationHandler(serviceBean);
}

private void initReferenceBeanInvocationHandler(ServiceBean serviceBean) {
    String serviceBeanName = serviceBean.getBeanName();
    // Remove ServiceBean when it's exported
    // 从 localReferenceBeanInvocationHandlerCache 缓存中,移除
    ReferenceBeanInvocationHandler handler = localReferenceBeanInvocationHandlerCache.remove(serviceBeanName);
    // Initialize
    // 执行初始化
    if (handler != null) {
        handler.init();
    }
}

private void onContextRefreshedEvent(ContextRefreshedEvent event) {
}
  • 重点在于处理 ServiceBeanExportedEvent 事件。处理时,如果判断 localReferenceBeanInvocationHandlerCache 中存在 ReferenceBeanInvocationHandler 对象,说明有它未初始化。后续,调用 ReferenceBeanInvocationHandler#init() 方法,从而完成。这块,胖友结合 「5.2.2 doGetInjectedBean」 一起,是不是就明白了。
  • 在 ServiceBean 暴露服务完成后,会发布 ServiceBeanExportedEvent 事件。代码如下:

    // ServiceBean.java
    
    private ApplicationEventPublisher applicationEventPublisher;
    
    /**
     * @since 2.6.5
     */
    @Override
    public void export() {
        // 暴露服务
        super.export();
        // Publish ServiceBeanExportedEvent
        // 发布事件
        publishExportEvent();
    }
    
    /**
     * @since 2.6.5
     */
    private void publishExportEvent() {
        // 创建 ServiceBeanExportedEvent 对象
        ServiceBeanExportedEvent exportEvent = new ServiceBeanExportedEvent(this);
        // 发布事件
        applicationEventPublisher.publishEvent(exportEvent);
    }
    
  • org.apache.dubbo.config.spring.context.event.ServiceBeanExportedEvent ,Service Bean 暴露完成事件。代码如下:

    // BeanExportedEvent.java
    
    /**
     * A {@link ApplicationEvent} after {@link ServiceBean} {@link ServiceBean#export() export} invocation
     *
     * @see ApplicationEvent
     * @see ApplicationListener
     * @see ServiceBean
     * @since 2.6.5
     */
    public class ServiceBeanExportedEvent extends ApplicationEvent {
    
        /**
         * Create a new ApplicationEvent.
         *
         * @param serviceBean {@link ServiceBean} bean
         */
        public ServiceBeanExportedEvent(ServiceBean serviceBean) {
            super(serviceBean);
        }
    
        /**
         * Get {@link ServiceBean} instance
         *
         * @return non-null
         */
        public ServiceBean getServiceBean() {
            return (ServiceBean) super.getSource();
        }
    
    }
    

5.3.4 ReferenceBeanBuilder

org.apache.dubbo.config.spring.beans.factory.annotation.ReferenceBeanBuilder ,继承 AbstractAnnotationConfigBeanBuilder 抽象类,ReferenceBean 的构建器。

考虑到 ReferenceBeanBuilder 类,就是 #build() 方法,我们就直接结合 AbstractAnnotationConfigBeanBuilder 抽象类,一起写了。

5.3.4.1 构造方法

// AbstractAnnotationConfigBeanBuilder.java

abstract class AbstractAnnotationConfigBeanBuilder {

    /**
     * 注解
     */
    protected final A annotation;
    
    protected final ApplicationContext applicationContext;
    
    protected final ClassLoader classLoader;
    
    /**
     * Bean 对象
     */
    protected Object bean;
    /**
     * 接口
     */
    protected Class interfaceClass;
    
    protected AbstractAnnotationConfigBeanBuilder(A annotation, ClassLoader classLoader,
                                                  ApplicationContext applicationContext) {
        Assert.notNull(annotation, "The Annotation must not be null!");
        Assert.notNull(classLoader, "The ClassLoader must not be null!");
        Assert.notNull(applicationContext, "The ApplicationContext must not be null!");
        this.annotation = annotation;
        this.applicationContext = applicationContext;
        this.classLoader = classLoader;
    }
}

// ReferenceBeanBuilder.java

class ReferenceBeanBuilder extends AbstractAnnotationConfigBeanBuilder {

    private ReferenceBeanBuilder(Reference annotation, ClassLoader classLoader, ApplicationContext applicationContext) {
        super(annotation, classLoader, applicationContext);
    }

    public static ReferenceBeanBuilder create(Reference annotation, ClassLoader classLoader, ApplicationContext applicationContext) {
        return new ReferenceBeanBuilder(annotation, classLoader, applicationContext);
    }
    
}
  • 其中,泛型 A 对应 @Reference 注解,泛型 B 对应 ReferenceBean 类。

5.3.4.2 build

#build() 方法,构造泛型 B 对象。此处,就是构造 ReferenceBean 对象。代码如下:

// AbstractAnnotationConfigBeanBuilder.java

public final B build() throws Exception {
    // 校验依赖
    checkDependencies();
    // 执行构造 Bean 对象
    B bean = doBuild();
    // 配置 Bean 对象
    configureBean(bean);
    if (logger.isInfoEnabled()) {
        logger.info("The bean[type:" + bean.getClass().getSimpleName() + "] has been built.");
    }
    return bean;
}

private void checkDependencies() {
}

/**
 * Builds {@link B Bean}
 *
 * @return {@link B Bean}
 */
protected abstract B doBuild();


protected void configureBean(B bean) throws Exception {
    // 前置配置
    preConfigureBean(annotation, bean);

    // 配置 RegistryConfig 属性
    configureRegistryConfigs(bean);
    // 配置 MonitorConfig 属性
    configureMonitorConfig(bean);
    // 配置 ApplicationConfig 属性
    configureApplicationConfig(bean);
    // 配置 ModuleConfig 属性
    configureModuleConfig(bean);

    // 后置配置
    postConfigureBean(annotation, bean);
}

protected abstract void preConfigureBean(A annotation, B bean) throws Exception; // 抽象方法

private void configureRegistryConfigs(B bean) {
    String[] registryConfigBeanIds = resolveRegistryConfigBeanNames(annotation);
    List registryConfigs = BeanFactoryUtils.getBeans(applicationContext, registryConfigBeanIds, RegistryConfig.class);
    bean.setRegistries(registryConfigs);
}

private void configureMonitorConfig(B bean) {
    String monitorBeanName = resolveMonitorConfigBeanName(annotation);
    MonitorConfig monitorConfig = BeanFactoryUtils.getOptionalBean(applicationContext, monitorBeanName, MonitorConfig.class);
    bean.setMonitor(monitorConfig);
}

private void configureApplicationConfig(B bean) {
    String applicationConfigBeanName = resolveApplicationConfigBeanName(annotation);
    ApplicationConfig applicationConfig = BeanFactoryUtils.getOptionalBean(applicationContext, applicationConfigBeanName, ApplicationConfig.class);
    bean.setApplication(applicationConfig);
}

private void configureModuleConfig(B bean) {
    String moduleConfigBeanName = resolveModuleConfigBeanName(annotation);
    ModuleConfig moduleConfig = BeanFactoryUtils.getOptionalBean(applicationContext, moduleConfigBeanName, ModuleConfig.class);
    bean.setModule(moduleConfig);
}

protected abstract String resolveModuleConfigBeanName(A annotation); // 抽象方法
protected abstract String resolveApplicationConfigBeanName(A annotation); // 抽象方法
protected abstract String[] resolveRegistryConfigBeanNames(A annotation); // 抽象方法
protected abstract String resolveMonitorConfigBeanName(A annotation); // 抽象方法

protected abstract void postConfigureBean(A annotation, B bean) throws Exception; // 抽象方法
  • ReferenceBeanBuilder 主要对上面的抽象方法,进行具体实现。代码如下:

    // ReferenceBeanBuilder.java
    
    static final String[] IGNORE_FIELD_NAMES = of("application", "module", "consumer", "monitor", "registry")
    
    @Override
    protected ReferenceBean doBuild() {
        // 创建 ReferenceBean 对象
        return new ReferenceBean<>();
    }
    
    @SuppressWarnings("Duplicates")
    @Override
    protected void preConfigureBean(Reference reference, ReferenceBean referenceBean) {
        Assert.notNull(interfaceClass, "The interface class must set first!");
    
        // 创建 DataBinder 对象
        DataBinder dataBinder = new DataBinder(referenceBean);
        // Register CustomEditors for special fields
        // 注册指定属性的自定义 Editor
        dataBinder.registerCustomEditor(String.class, "filter", new StringTrimmerEditor(true));
        dataBinder.registerCustomEditor(String.class, "listener", new StringTrimmerEditor(true));
        dataBinder.registerCustomEditor(Map.class, "parameters", new PropertyEditorSupport() {
            @Override
            public void setAsText(String text) throws java.lang.IllegalArgumentException {
                // Trim all whitespace
                String content = StringUtils.trimAllWhitespace(text);
                if (!StringUtils.hasText(content)) { // No content , ignore directly
                    return;
                }
                // replace "=" to ","
                content = StringUtils.replace(content, "=", ",");
                // replace ":" to ","
                content = StringUtils.replace(content, ":", ",");
                // String[] to Map
                Map parameters = CollectionUtils.toStringMap(commaDelimitedListToStringArray(content));
                setValue(parameters);
            }
        });
    
        // Bind annotation attributes
        // 将注解的属性,设置到 reference 中
        dataBinder.bind(new AnnotationPropertyValuesAdapter(reference, applicationContext.getEnvironment(), IGNORE_FIELD_NAMES));
    }
    
    
    @Override
    protected String resolveModuleConfigBeanName(Reference annotation) {
        return annotation.module();
    }
    
    @Override
    protected String resolveApplicationConfigBeanName(Reference annotation) {
        return annotation.application();
    }
    
    @Override
    protected String[] resolveRegistryConfigBeanNames(Reference annotation) {
        return annotation.registry();
    }
    
    @Override
    protected String resolveMonitorConfigBeanName(Reference annotation) {
        return annotation.monitor();
    }
    
    @Override
    protected void postConfigureBean(Reference annotation, ReferenceBean bean) throws Exception {
        // 设置 applicationContext
        bean.setApplicationContext(applicationContext);
        // 配置 interfaceClass
        configureInterface(annotation, bean);
        // 配置 ConsumerConfig
        configureConsumerConfig(annotation, bean);
    
        // 执行 Bean 后置属性初始化
        bean.afterPropertiesSet();
    }
    
    @SuppressWarnings("Duplicates")
    private void configureInterface(Reference reference, ReferenceBean referenceBean) {
        // 首先,从 @Reference 获得 interfaceName 属性,从而获得 interfaceClass 类
        Class interfaceClass = reference.interfaceClass();
        if (void.class.equals(interfaceClass)) {
            interfaceClass = null;
            String interfaceClassName = reference.interfaceName();
            if (StringUtils.hasText(interfaceClassName)) {
                if (ClassUtils.isPresent(interfaceClassName, classLoader)) {
                    interfaceClass = ClassUtils.resolveClassName(interfaceClassName, classLoader);
                }
            }
    
        }
    
        // 如果获得不到,则使用 interfaceClass 即可
        if (interfaceClass == null) {
            interfaceClass = this.interfaceClass;
        }
    
        Assert.isTrue(interfaceClass.isInterface(), "The class of field or method that was annotated @Reference is not an interface!");
        referenceBean.setInterface(interfaceClass);
    }
    
    
    private void configureConsumerConfig(Reference reference, ReferenceBean referenceBean) {
        // 获得 ConsumerConfig 对象
        String consumerBeanName = reference.consumer();
        ConsumerConfig consumerConfig = getOptionalBean(applicationContext, consumerBeanName, ConsumerConfig.class);
        // 设置到 referenceBean 中
        referenceBean.setConsumer(consumerConfig);
    }
    
    • ~

写的相对简略。胖友注意看每一个的注释哈~

5.3.5 destroy

实现 #destroy() 方法,执行销毁逻辑。代码如下:

// ReferenceAnnotationBeanPostProcessor.java

@Override
public void destroy() throws Exception {
    // 父类销毁
    super.destroy();
    // 清空缓存
    this.referenceBeanCache.clear();
    this.localReferenceBeanInvocationHandlerCache.clear();
    this.injectedFieldReferenceBeanCache.clear();
    this.injectedMethodReferenceBeanCache.clear();
}

你可能感兴趣的:(微服务框架)