前言

git clone https://github.com/AvengerEug/dubbo.git -b dubbo-2.7.3-myself
  • 源码是我Fork过来了,没有做任何改动。可以放心clone 废话不多说,直接看源码。

一、官网dubbo-demo-annotation模块

  • 源码clone下来后,可以进入根目录执行mvn clean install -Dmaven.test.skip=true命令来编译项目(这里要跳过测试步骤)
  • 找到dubbo-demo/dubbo-demo-annotation/dubbo-demo-annotation-provider模块,并打开Application.java文件,如下图:

    我只是把我的注册中心的配置改成了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
  2. dubbo的服务接口_apache

  3. EnableDubboConfig.java
  4. dubbo的服务接口_spring_02

  5. DubboComponentScan.java

    通过以上可知,实际上就是两个注解在起作用:(@Import(DubboConfigConfigurationRegistrar.class)和@Import(DubboComponentScanRegistrar.class)) ,最终他们内部执行了如下四个注解类似的功能,即把四个class类给添加到spring容器(目的就是为了加载添加到spring容器中的dubbo相关的配置bean)。
@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方法

  • 如下图, 同理,第一次执行的肯定是ConfigurationClassPostProcessor
  • dubbo的服务接口_spring_03

  • 执行完ConfigurationClassPostProcessor的postProcessBeanDefinitionRegistry方法后,spring能扫描到的、配置类导入的任何类都以BeanDefinition的形式存在bean工厂了(除开使用后置处理器手动添加bean的情况),所以此时,@EnableDubbo注解导入的五个beanDefinition(因为还有一个带@Bean的方法)肯定在bean工厂中(注意: 此时bean并还没有被生成), 如下图所示:
  • dubbo的服务接口_spring_04


ok。按照逻辑走,接下来就会执行除开ConfigurationClassPostProcessor并且实现了Ordered接口的后置处理器了,因为ServiceAnnotationBeanPostProcessor并没有实现Ordered接口,于是会去执行没有实现PriorityOrderedOrdered接口的后置处理器(咦,不就是ServiceAnnotationBeanPostProcessor,终于轮到他了)。

dubbo的服务接口_dubbo的服务接口_05


于是,我们直接定位到ServiceAnnotationBeanPostProcessor中的postProcessBeanDefinitionRegistry方法。

源码如下:

public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
		
        // packagesToScan为@EnableDubbo注解中指定的scanBasePackages参数值处理过后的变量
        Set<String> 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<String> 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<BeanDefinitionHolder> 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的工作。同样的,它也没实现PriorityOrderedOrdered接口,直接看执行无实现接口的逻辑,如图:
  • dubbo的服务接口_spring_06

  • 综上所述: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.