Dubbo2.7.3版本源码学习系列二: Dubbo服务提供者@EnableDubbo注解ServiceAnnotationBeanPostProcessor原理

前言

  • 上篇博客Dubbo2.7.3版本源码学习系列一: 初始Dubbo利用SPI机制实现AOP和IOC的源码分析我们详细了解了Dubbo的一些SPI扩展机制。接下来我们学习一下Dubbo注解版本的@EnableDubbo注解实现原理(此注解结合了spring的相关知识点,需要有spring基础的才能看懂。本人总结过spring相关一些常用知识点。传送门)
  • 准备工作: 需要拉取Dubbo 2.7.3版本的源码, 可以执行如下操作
    git clone https://github.com/AvengerEug/dubbo.git -b dubbo-2.7.3
    
    源码是我Fork过来了,没有做任何改动。可以放心clone
    废话不多说,直接看源码。

一、官网dubbo-demo-annotation模块

  • 源码clone下来后,可以进入根目录执行mvn clean install -Dmaven.test.skip=true命令来编译项目(这里要跳过测试步骤)
  • 找到dubbo-demo/dubbo-demo-annotation/dubbo-demo-annotation-provider模块,并打开Application.java文件,如下图:
    Dubbo2.7.3版本源码学习系列二: Dubbo服务提供者@EnableDubbo注解ServiceAnnotationBeanPostProcessor原理_第1张图片
    我只是把我的注册中心的配置改成了zookeeper, 不改应该也没关系。
    通过Application.java文件可以看到,内部维护了一个静态类ProviderConfiguration, 并将此静态类作为参数传递到了AnnotationConfigApplicationContext中。看过我之前的spring相关的博客的话,应该能明白,这是注册了一个beanDefinition。其实很简单。当执行完内部的register方法后,spring bean工厂DefaultListableBeanFactory中就会多一条beanDefinition。即一共是7条(在之前的博客中有讲到,这里就不多阐述了)。当spring执行refresh方法并执行到内部的invokeBeanFactoryPostProcessors方法时,则会去解析配置类(之前的spring系列也讲过)。此时只有传入的ProviderConfiguration是配置类,于是开始解析它。解析的过程呢,就会去解析它的@PropertySource注解@ComponentScan@Import@ImportResource@Bean标识的方法,除了@ComponentScan注解会立即扫描类并把它们变成beanDefinition加载到bean工厂外,其他的几个注解都是先存到一个集合,后续再统一处理。了解了这么一个流程后,我们再看一下@EnableDubbo注解长什么样。
  1. EnableDubbo.java
    Dubbo2.7.3版本源码学习系列二: Dubbo服务提供者@EnableDubbo注解ServiceAnnotationBeanPostProcessor原理_第2张图片

  2. EnableDubboConfig.java
    Dubbo2.7.3版本源码学习系列二: Dubbo服务提供者@EnableDubbo注解ServiceAnnotationBeanPostProcessor原理_第3张图片

  3. DubboComponentScan.java
    Dubbo2.7.3版本源码学习系列二: Dubbo服务提供者@EnableDubbo注解ServiceAnnotationBeanPostProcessor原理_第4张图片
    通过以上可知,实际上就是两个注解在起作用:

    @Import(DubboConfigConfigurationRegistrar.class)
    @Import(DubboComponentScanRegistrar.class)
    @Import(DubboConfigBindingsRegistrar.class)
    @Import(DubboConfigBindingRegistrar.class)
    

    这四个类长什么样就不展示了,直接展示下这四个类分别作了些什么事:

    DubboConfigConfigurationRegistrar.java

    事件 注意事项 beanName
    注册DubboConfigConfiguration.Single内部类的BeanDefinition 此内部类中被Dubbo的自定义注解@EnableDubboConfigBindings和@EnableDubboConfigBinding标识 => 此注解又@Import了两个类分别是DubboConfigBindingBeanPostProcessor和DubboConfigBindingsBeanPostProcessor dubboConfigConfiguration.Single
    注册DubboConfigConfiguration.Multiple bean内部类的BeanDefinition 此内部类中被Dubbo的自定义注解@EnableDubboConfigBindings和@EnableDubboConfigBinding标识 => 此注解又@Import了两个类分别是DubboConfigBindingBeanPostProcessor和DubboConfigBindingsBeanPostProcessor dubboConfigConfiguration.Multiple

    DubboComponentScanRegistrar.java

    事件 注意事项 beanName
    注册ServiceAnnotationBeanPostProcessor的BeanDefinition 此类实现了BeanDefinitionRegistryPostProcessor接口,并且在DubboComponentScanRegistrar中指定了ServiceAnnotationBeanPostProcessor的bean要使用一个参数的构造方法进行构建,参数值为注解中的@EnableDubbo注解中的scanBasePackages方法决定 org.apache.dubbo.config.spring.beans.factory.annotation.ServiceAnnotationBeanPostProcessor#0
    注册ReferenceAnnotationBeanPostProcessor的BeanDefinition 此类实现了AnnotationInjectedBeanPostProcessor、ApplicationListener接口。且对ServiceBeanExportedEvent和ContextRefreshedEvent事件感兴趣 referenceAnnotationBeanPostProcessor

    DubboConfigBindingRegistrar.java和DubboConfigBindingsRegistrar.java统一做了如下事

    事件 注意事项 beanName
    注册ApplicationConfig的beanDefinition 无配置dubbo.application的相关配置时,则不注册bean org.apache.dubbo.config.ApplicationConfig#0
    注册ModuleConfig的beanDefinition 无配置dubbo.module的相关配置时,则不注册bean org.apache.dubbo.config.ModuleConfig#0
    注册RegistryConfig的beanDefinition 无配置dubbo.registry的相关配置时,则不注册bean org.apache.dubbo.config.RegistryConfig#0
    注册ProtocolConfig的beanDefinition 无配置dubbo.protocol的相关配置时,则不注册bean org.apache.dubbo.config.ProtocolConfig#0
    注册MonitorConfig的beanDefinition 无配置dubbo.monitor的相关配置时,则不注册bean org.apache.dubbo.config.MonitorConfig#0
    注册ProviderConfig的beanDefinition 无配置dubbo.provider的相关配置时,则不注册bean org.apache.dubbo.config.ProviderConfig#0
    注册ConsumerConfig的beanDefinition 无配置dubbo.consumer的相关配置时,则不注册bean org.apache.dubbo.config.ConsumerConfig#0
    注册ConfigCenterBean的beanDefinition 无配置dubbo.config-center的相关配置时,则不注册bean org.apache.dubbo.config.ConfigCenterBean#0
    注册MetadataReportConfig的beanDefinition 无配置dubbo.metadata-report的相关配置时,则不注册bean org.apache.dubbo.config.MetadataReportConfig#0
    注册DubboConfigBindingBeanPostProcessor的beanDefinition 管理Dubbo配置的后置处理器 org.apache.dubbo.config.spring.beans.factory.annotation.DubboConfigBindingBeanPostProcessor
    注册NamePropertyDefaultValueDubboConfigBeanCustomizer 自定义的配置类处理器,所有的配置类会共用它 namePropertyDefaultValueDubboConfigBeanCustomizer

    由上面的表格可以知道,@EnableDubbo注解向spring中注册了至少5个BeanDefinition(其他的beanDefinition都是基于配置是否存在),其中,我们先关注ServiceAnnotationBeanPostProcessor。为什么呢?不知道大家还记得ConfigurationClassPostProcessor类吗?这个类我专门写了两篇博客来介绍他!它之所以那么强就是因为它实现了BeanDefinitionRegistryPostProcessor接口。而如今,@EnableDubbo注解也往spring注册了一个实现了这个接口的bean — ServiceAnnotationBeanPostProcessor,所以我猜测他应该是作为Dubbo服务提供者的入口的。所以我们立马定位到invokeBeanFactoryPostProcessors方法中去, 最终会调用PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors方法。此方法我在之前也特意总结过,包括他加载后置处理器的顺序,等等。

二、PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors方法

  • 如下图, 同理,第一次执行的肯定是ConfigurationClassPostProcessorDubbo2.7.3版本源码学习系列二: Dubbo服务提供者@EnableDubbo注解ServiceAnnotationBeanPostProcessor原理_第5张图片
    执行完ConfigurationClassPostProcessor的postProcessBeanDefinitionRegistry方法后,spring能扫描到的、配置类导入的任何类都以BeanDefinition的形式存在bean工厂了(除开使用后置处理器手动添加bean的情况),所以此时,@EnableDubbo注解导入的五个beanDefinition(因为还有一个带@Bean的方法)肯定在bean工厂中(注意: 此时bean并还没有被生成), 如下图所示:
    Dubbo2.7.3版本源码学习系列二: Dubbo服务提供者@EnableDubbo注解ServiceAnnotationBeanPostProcessor原理_第6张图片

ok。按照逻辑走,接下来就会执行除开ConfigurationClassPostProcessor并且实现了Ordered接口的后置处理器了,因为ServiceAnnotationBeanPostProcessor并没有实现Ordered接口,于是会去执行没有实现PriorityOrderedOrdered接口的后置处理器(咦,不就是ServiceAnnotationBeanPostProcessor,终于轮到他了)。
Dubbo2.7.3版本源码学习系列二: Dubbo服务提供者@EnableDubbo注解ServiceAnnotationBeanPostProcessor原理_第7张图片
于是,我们直接定位到ServiceAnnotationBeanPostProcessor中的postProcessBeanDefinitionRegistry方法。
源码如下:
```java
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {

    // packagesToScan为@EnableDubbo注解中指定的scanBasePackages参数值处理过后的变量
    Set resolvedPackagesToScan = resolvePackagesToScan(packagesToScan);

    if (!CollectionUtils.isEmpty(resolvedPackagesToScan)) {
        // 开始注册指定路径的值
        registerServiceBeans(resolvedPackagesToScan, registry);
    } else {
        if (logger.isWarnEnabled()) {
            logger.warn("packagesToScan is empty , ServiceBean registry will be ignored!");
        }
    }

}

private void registerServiceBeans(Set packagesToScan, BeanDefinitionRegistry registry) {

   // Dubbo自己实现了一个扫描器,mybatis也自己实现了。不知道自己能不能实现,哈哈哈~~~
    DubboClassPathBeanDefinitionScanner scanner =
            new DubboClassPathBeanDefinitionScanner(registry, environment, resourceLoader);

    // 获取一个创建bean name的生成器
    BeanNameGenerator beanNameGenerator = resolveBeanNameGenerator(registry);
    scanner.setBeanNameGenerator(beanNameGenerator);

    // 表示扫描的类要包含org.apache.dubbo.config.annotation.Service注解
    scanner.addIncludeFilter(new AnnotationTypeFilter(Service.class));

    // 为了兼容,也识别alibaba jar包中的Service注解
    scanner.addIncludeFilter(new AnnotationTypeFilter(com.alibaba.dubbo.config.annotation.Service.class));

    for (String packageToScan : packagesToScan) {

        // 扫描指定路径下带上述两个注解的类
        scanner.scan(packageToScan);

        // Finds all BeanDefinitionHolders of @Service whether @ComponentScan scans or not.
        // 在这一步主要是把扫描出来的beanDefinition变成BeanDefinitionHolder的包装类
        Set beanDefinitionHolders =
                findServiceBeanDefinitionHolders(scanner, packageToScan, registry, beanNameGenerator);

        if (!CollectionUtils.isEmpty(beanDefinitionHolders)) {

            for (BeanDefinitionHolder beanDefinitionHolder : beanDefinitionHolders) {
                // 将所有的包装类注册至bean工厂
                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 + "]");
            }

        }

    }
}
```
ok. `ServiceAnnotationBeanPostProcessor`作为**BeanDefinitionRegistryPostProcessor**角色的工作就完成了。按照`invokeBeanFactoryPostProcessors`方法的逻辑,现在还需要去执行角色为`BeanFactoryPostProcessor`的工作。同样的,它也没实现`PriorityOrdered`和`Ordered`接口,直接看执行无实现接口的逻辑,如图: ![在这里插入图片描述](https://img-blog.csdnimg.cn/20200405155134994.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2F2ZW5nZXJFdWc=,size_16,color_FFFFFF,t_70)
综上所述:`ServiceAnnotationBeanPostProcessor`的作用就是将Dubbo自实现的@Service标识的类注册到bean工厂去,由spring去生成bean。好了,写了那么大一篇幅来描述`ServiceAnnotationBeanPostProcessor`, 那剩下的三个该怎么搞咯?别急嘛,这三个都总结完了,那Dubbo注解版本与spring相关的部分就结束了。。。剩下的三个,后面再更新。。

三、总结

  • 本次博客主要总结了@EnabbleDubbo注解在服务提供方的具体作用,即通过ServiceAnnotationBeanPostProcessor后置处理器扫描指定包下所有带Dubbo自己开发的@Service注解的类加载到spring中去。顺便温故了一波spring的相关知识点
  • I am a slow walker, but I never walk backwards.

你可能感兴趣的:(Dubbo)