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-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. EnableDubboConfig.java
    在这里插入图片描述

  3. 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和DubboConfigBindingsBeanPostProcessordubboConfigConfiguration.Single
    注册DubboConfigConfiguration.Multiple bean内部类的BeanDefinition此内部类中被Dubbo的自定义注解@EnableDubboConfigBindings和@EnableDubboConfigBinding标识 => 此注解又@Import了两个类分别是DubboConfigBindingBeanPostProcessor和DubboConfigBindingsBeanPostProcessordubboConfigConfiguration.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的相关配置时,则不注册beanorg.apache.dubbo.config.ApplicationConfig#0
    注册ModuleConfig的beanDefinition无配置dubbo.module的相关配置时,则不注册beanorg.apache.dubbo.config.ModuleConfig#0
    注册RegistryConfig的beanDefinition无配置dubbo.registry的相关配置时,则不注册beanorg.apache.dubbo.config.RegistryConfig#0
    注册ProtocolConfig的beanDefinition无配置dubbo.protocol的相关配置时,则不注册beanorg.apache.dubbo.config.ProtocolConfig#0
    注册MonitorConfig的beanDefinition无配置dubbo.monitor的相关配置时,则不注册beanorg.apache.dubbo.config.MonitorConfig#0
    注册ProviderConfig的beanDefinition无配置dubbo.provider的相关配置时,则不注册beanorg.apache.dubbo.config.ProviderConfig#0
    注册ConsumerConfig的beanDefinition无配置dubbo.consumer的相关配置时,则不注册beanorg.apache.dubbo.config.ConsumerConfig#0
    注册ConfigCenterBean的beanDefinition无配置dubbo.config-center的相关配置时,则不注册beanorg.apache.dubbo.config.ConfigCenterBean#0
    注册MetadataReportConfig的beanDefinition无配置dubbo.metadata-report的相关配置时,则不注册beanorg.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在这里插入图片描述
    执行完ConfigurationClassPostProcessor的postProcessBeanDefinitionRegistry方法后,spring能扫描到的、配置类导入的任何类都以BeanDefinition的形式存在bean工厂了(除开使用后置处理器手动添加bean的情况),所以此时,@EnableDubbo注解导入的五个beanDefinition(因为还有一个带@Bean的方法)肯定在bean工厂中(注意: 此时bean并还没有被生成), 如下图所示:
    在这里插入图片描述

ok。按照逻辑走,接下来就会执行除开ConfigurationClassPostProcessor并且实现了Ordered接口的后置处理器了,因为ServiceAnnotationBeanPostProcessor并没有实现Ordered接口,于是会去执行没有实现PriorityOrderedOrdered接口的后置处理器(咦,不就是ServiceAnnotationBeanPostProcessor,终于轮到他了)。
在这里插入图片描述
于是,我们直接定位到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接口,直接看执行无实现接口的逻辑,如图: 在这里插入图片描述
    综上所述: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.
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值