Dubbo源码—— @EnableDubbo注解实现原理分析

1,633 阅读4分钟

我们知道在使用dubbo时候,(如果是注解方式的话)需要开启 @EnableDubbo注解,并且在服务提供者的类上加上@Service, 在服务调用者类上加上@Referce注解,那么其内部是如何工作的呢?

1. @EnableDubbo组成

@EnableDubbo=@DubboComponentScan+@EnableDubboConfig

我们看到@EnableDubbo内部并没有什么,只是把@DubboComponentScan和@EnableDubboConfig合二为一了,其中

@DubboComponentScan是对注解 @Service@Referce的处理 (主要是将这俩货交给spring容器),

@EnableDubboConfig则是开启读取配置文件,读取我们自定义的配置信息。


/**
 * Enables Dubbo components as Spring Beans, equals
 * {@link DubboComponentScan} and {@link EnableDubboConfig} combination.
 * <p>
 * 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
@DubboComponentScan
public @interface EnableDubbo {

    /**
     * Base packages to scan for annotated @Service classes.
     * <p>
     * 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 {};

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


    /**
     * It indicates whether {@link AbstractConfig} binding to multiple Spring Beans.
     *
     * @return the default value is <code>false</code>
     * @see EnableDubboConfig#multiple()
     */
    @AliasFor(annotation = EnableDubboConfig.class, attribute = "multiple")
    boolean multipleConfig() default true;

}

接下来我们分别分析 @DubboComponentScan 和 @EnableDubboConfig 注解的实现方式


1.1 @DubboComponentScan (作用: 将@Service和@Referce修饰的类注册到spring容器中去)

源码 EnableDubbo类中的注释为 "启用 Dubbo 组件作为 Spring Beans" 其实都一个意思) , 

看下DubboComponentScan,定义如下:

image.png

除了从注释中略知该类的作用,我们还发现重要的一句 @Import(DubboComponentScanRegistrar.class),到这里对spring熟悉的同学相信已经猜到了,@Service @Referce注解是通过@Import的方式注册到spring中去的。ok接下来我们看下具体的逻辑。

1.1.1 DubboComponentScanRegistrar

看下其源码我们发现他实现了 ImportBeanDefinitionRegistrar接口,关于这个请看 我的另一篇文章--->>>使用@Import注册bean到Spring容器中 的介绍。

  • 首先我们看下这个类(DubboComponentScanRegistrar)的代码:
/**
 * Dubbo {@link DubboComponentScan} Bean Registrar
 *
 * @see Service
 * @see DubboComponentScan
 * @see ImportBeanDefinitionRegistrar
 * @see ServiceAnnotationBeanPostProcessor
 * @see ReferenceAnnotationBeanPostProcessor
 * @since 2.5.7
 */
public class DubboComponentScanRegistrar implements ImportBeanDefinitionRegistrar {

    @Override
    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
        //解析要扫描的包 这里解析的是 @DubboComponentScan注解的 basePackages属性对应的值
        Set<String> packagesToScan = getPackagesToScan(importingClassMetadata);
        //注册 处理 Service 注解的BeanDefinition 到 DefaultListableBeanFactory的 beanDefinitionMap 成员变量中去
        registerServiceAnnotationBeanPostProcessor(packagesToScan, registry);
        //注册 处理 Reference 注解的BeanDefinition 到 DefaultListableBeanFactory的 beanDefinitionMap 成员变量中去
        registerReferenceAnnotationBeanPostProcessor(registry);

    }

    /**
     * Registers {@link ServiceAnnotationBeanPostProcessor}
     *
     * @param packagesToScan packages to scan without resolving placeholders
     * @param registry       {@link BeanDefinitionRegistry}
     * @since 2.5.8
     */
    private void registerServiceAnnotationBeanPostProcessor(Set<String> packagesToScan, BeanDefinitionRegistry registry) {

        BeanDefinitionBuilder builder = rootBeanDefinition(ServiceAnnotationBeanPostProcessor.class);
        builder.addConstructorArgValue(packagesToScan);
        builder.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
        AbstractBeanDefinition beanDefinition = builder.getBeanDefinition();
        BeanDefinitionReaderUtils.registerWithGeneratedName(beanDefinition, registry);

    }

    /**
     * Registers {@link ReferenceAnnotationBeanPostProcessor} into {@link BeanFactory}
     *
     * @param registry {@link BeanDefinitionRegistry}
     */
    private void registerReferenceAnnotationBeanPostProcessor(BeanDefinitionRegistry registry) {

        // Register @Reference Annotation Bean Processor
        BeanRegistrar.registerInfrastructureBean(registry,
                ReferenceAnnotationBeanPostProcessor.BEAN_NAME, ReferenceAnnotationBeanPostProcessor.class);

    }

    private Set<String> getPackagesToScan(AnnotationMetadata metadata) {
        AnnotationAttributes attributes = AnnotationAttributes.fromMap(
                metadata.getAnnotationAttributes(DubboComponentScan.class.getName()));
        String[] basePackages = attributes.getStringArray("basePackages");
        Class<?>[] basePackageClasses = attributes.getClassArray("basePackageClasses");
        String[] value = attributes.getStringArray("value");
        // Appends value array attributes
        Set<String> packagesToScan = new LinkedHashSet<String>(Arrays.asList(value));
        packagesToScan.addAll(Arrays.asList(basePackages));
        for (Class<?> basePackageClass : basePackageClasses) {
            packagesToScan.add(ClassUtils.getPackageName(basePackageClass));
        }
        if (packagesToScan.isEmpty()) {
            return Collections.singleton(ClassUtils.getPackageName(metadata.getClassName()));
        }
        return packagesToScan;
    }

}

其中 最主要的逻辑都在 registerBeanDefinitions中

1.1.1.1 getPackagesToScan 没啥好说的,就是获取到scanBasePackages的值

image.png

1.1.1.2 registerServiceAnnotationBeanPostProcessor

该方法作用: 注册 处理@Service注解的BeanDefinition即(ServiceAnnotationBeanPostProcessor) 到 DefaultListableBeanFactory的 beanDefinitionMap 成员变量中去

第一步

image.png

第二步 注册bean定义信息到

image.png

往下走: 到了 DefaultListableBeanFactoryregisterBeanDefinition 方法 , 这是一个很重要的方法,几乎所有bean定义信息都是经过这个方法注册到DefaultListableBeanFactorybeanDefinitionMap中去的。


//beanDefinitionMap成员变量
private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap(256);
public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition) throws BeanDefinitionStoreException {
    Assert.hasText(beanName, "Bean name must not be empty");
    Assert.notNull(beanDefinition, "BeanDefinition must not be null");
    if (beanDefinition instanceof AbstractBeanDefinition) {
        try {
            ((AbstractBeanDefinition)beanDefinition).validate();
        } catch (BeanDefinitionValidationException var9) {
            throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName, "Validation of bean definition failed", var9);
        }
    }

    BeanDefinition oldBeanDefinition = (BeanDefinition)this.beanDefinitionMap.get(beanName);
    if (oldBeanDefinition != null) {
        if (!this.isAllowBeanDefinitionOverriding()) {
            throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName, "Cannot register bean definition [" + beanDefinition + "] for bean '" + beanName + "': There is already [" + oldBeanDefinition + "] bound.");
        }

        if (oldBeanDefinition.getRole() < beanDefinition.getRole()) {
            if (this.logger.isWarnEnabled()) {
                this.logger.warn("Overriding user-defined bean definition for bean '" + beanName + "' with a framework-generated bean definition: replacing [" + oldBeanDefinition + "] with [" + beanDefinition + "]");
            }
        } else if (!beanDefinition.equals(oldBeanDefinition)) {
            if (this.logger.isInfoEnabled()) {
                this.logger.info("Overriding bean definition for bean '" + beanName + "' with a different definition: replacing [" + oldBeanDefinition + "] with [" + beanDefinition + "]");
            }
        } else if (this.logger.isDebugEnabled()) {
            this.logger.debug("Overriding bean definition for bean '" + beanName + "' with an equivalent definition: replacing [" + oldBeanDefinition + "] with [" + beanDefinition + "]");
        }

        this.beanDefinitionMap.put(beanName, beanDefinition);
    } else {
        if (this.hasBeanCreationStarted()) {
            synchronized(this.beanDefinitionMap) {
                this.beanDefinitionMap.put(beanName, beanDefinition);
                List<String> updatedDefinitions = new ArrayList(this.beanDefinitionNames.size() + 1);
                updatedDefinitions.addAll(this.beanDefinitionNames);
                updatedDefinitions.add(beanName);
                this.beanDefinitionNames = updatedDefinitions;
                if (this.manualSingletonNames.contains(beanName)) {
                    Set<String> updatedSingletons = new LinkedHashSet(this.manualSingletonNames);
                    updatedSingletons.remove(beanName);
                    this.manualSingletonNames = updatedSingletons;
                }
            }
        } else {
            this.beanDefinitionMap.put(beanName, beanDefinition);
            this.beanDefinitionNames.add(beanName);
            this.manualSingletonNames.remove(beanName);
        }

        this.frozenBeanDefinitionNames = null;
    }

    if (oldBeanDefinition != null || this.containsSingleton(beanName)) {
        this.resetBeanDefinition(beanName);
    }

}

image.png

1.1.1.1 registerReferenceAnnotationBeanPostProcessor

注册 处理@Referen注解的BeanDefinition即(ReferenceAnnotationBeanPostProcessor) 到 DefaultListableBeanFactory的 beanDefinitionMap 成员变量中去

image.png 其实和 registerServiceAnnotationBeanPostProcessor 是一样的逻辑,就不过多赘述了。

1.1.1.3 接下来我们看下 ServiceAnnotationBeanPostProcessor(注意:在这个类中,才是真正的对@Service的扫描和bean定义信息注册)

重要方法 postProcessBeanDefinitionRegistry

/**
 *  这个接口在读取项目中的beanDefinition之后执行,提供一个补充的扩展点
 *  使用场景:你可以在这里动态注册自己的beanDefinition,可以加载classpath之外的bean
 *  时机: refresh()的 this.invokeBeanFactoryPostProcessors(beanFactory); 方法中执行
 *  此时 bean的定义信息 都已经加载完毕 但是还没到实例化以及初始化阶段
 *
 * @param registry
 * @throws BeansException
 */
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
    //解析包
    Set<String> resolvedPackagesToScan = resolvePackagesToScan(packagesToScan);

    if (!CollectionUtils.isEmpty(resolvedPackagesToScan)) {
        //触发ServiceBean定义和注入
        registerServiceBeans(resolvedPackagesToScan, registry);
    } else {
        if (logger.isWarnEnabled()) {
            logger.warn("packagesToScan is empty , ServiceBean registry will be ignored!");
        }
    }

}

image.png

可以看到 在容器刷新之后,会进行回调因为 ServiceAnnotationBeanPostProcessor 实现了 BeanDefinitionRegistryPostProcessor这个spring给我们预留的拓展(回调)方法。

接下来,我们继续看

image.png

创建针对dubbo的@Service的 扫描器

image.png

注意,如何让这个扫描器只扫描某些指定的注解呢?请看下图

image.png

调用父类,扫描指定包下的指定注解

image.png

查找 @Service 的所有 BeanDefinitionHolders,无论 @ComponentScan 是否扫描

image.png

image.png

image.png

1.1.1.3 最后放入DefaultListableBeanFactory的成员变量beanDefinitionMap中去,以便后续的bean对象创建成功并放入ioc供我们使用。

最终,我们看到会循环遍历 然后对扫描到的bean进行自动生成beanName,然后注册到 DefaultListableBeanFactory的成员变量beanDefinitionMap中去,在后续的bean创建时候,该@Service也就会交给spring管理了,说白了也就是会放到ioc容器中了。由此也就完成了dubbo和spring的结合。