美文网首页dubbo
Dubbo与Spring整合源码分析

Dubbo与Spring整合源码分析

作者: loveFXX | 来源:发表于2020-07-26 16:50 被阅读0次

    通过EnableDubbo和PropertySource开启了dubbo


    image.png

    PropertySource是spring的注解,用来指定配置文件路径

    EnableDubbo

    image.png

    @EnableDubboConfig注解用来将properties配置文件中的配置项转化为相对应的Bean
    @DubboComponentScan注解用来扫描服务提供者和引用者(@Service)

    1、EnableDubboConfig

    image.png

    1、导入DubboConfigConfigurationRegistrar类调用registerBeanDefinitions
    EnableDubboConfig注解中import导入DubboConfigConfigurationRegistrar类
    DubboConfigConfigurationRegistrar实现了ImportBeanDefinitionRegistrar类,这个类是Spring的扩展点之一,用来向spring容器中注册Bean,某个时机会调用到registerBeanDefinitions()方法
    org.apache.dubbo.config.spring.context.annotation.DubboConfigConfigurationRegistrar#registerBeanDefinitions


    image.png

    对于添加了EnableDubboConfig注解(添加了EnableDubbo注解)的类的元数据信息,便会得到EnableDubboConfig注解的属性值,根据属性值键值对可以获取multiple的属性值,默认multiple=true。用来决定是注册DubboConfigConfiguration.Single的Bean还是注册DubboConfigConfiguration.Multiple.class类型的Bean


    image.png
    2、multiple=true的意义
    以protocol为例,multiple=true的意义表示protocols有多种
    image.png
    3、Single和Multiple
    DubboConfigConfiguration.Single
    image.png

    DubboConfigConfiguration.Multiple


    image.png
    DubboConfigConfiguration.Single有两个注解:@EnableDubboConfigBindings和@EnableDubboConfigBinding
    Single和Multiple的唯一区别就是Multiple=true。
    4、EnableDubboConfigBindings
    导入DubboConfigBindingsRegistrar类
    image.png
    DubboConfigBindingsRegistrar实现了ImportBeanDefinitionRegistrar
    image.png
    image.png
    这个registerBeanDefinitions方法就是获取注解信息中@EnableDubboConfigBindings包含的@EnableDubboConfigBinding注解
    ,然后进行遍历注册调用DubboConfigBindingRegistrar的registerBeanDefinitions方法
    5、registerBeanDefinitions
    org.apache.dubbo.config.spring.context.annotation.DubboConfigBindingRegistrar#
    registerBeanDefinitions
    以dubbo.application配置为例,把前缀是dubbo.application的配置与type的class类型是org.apache.dubbo.config.ApplicationConfig注册一个XxxConfig配置Bean
    image.png

    6、registerDubboConfigBeans
    org.apache.dubbo.config.spring.context.annotation.DubboConfigBindingRegistrar#registerDubboConfigBeans


    image.png
    image.png
    ①、根据multiple的值,获取beanName
    如果multiple为false,则看有没有配置id属性,如果没有配置则自动生成一个
    org.apache.dubbo.config.spring.context.annotation.DubboConfigBindingRegistrar#
    resolveMultipleBeanNames
    image.png
    ②、如果配置有多个(multiple=true)则会为每个beanName都会注册一个BeanDefinition的配置类,这些配置了都实现了AbstractConfig
    ③、如果配置有多个(multiple=true)则为每个bean注册一个类型是DubboConfigBindingBeanPostProcessor的后置处理器
    a、registerDubboConfigBindingBeanPostProcessor
    org.apache.dubbo.config.spring.context.annotation.DubboConfigBindingRegistrar#
    registerDubboConfigBindingBeanPostProcessor
    image.png
    image.png
    DubboConfigBindingBeanPostProcessor实现了BeanPostProcessor, ApplicationContextAware, InitializingBean , BeanDefinitionRegistryPostProcessor
    b、postProcessBeforeInitialization
    org.apache.dubbo.config.spring.beans.factory.annotation.DubboConfigBindingBeanPostProcessor#
    postProcessBeforeInitialization
    这里是spring后置处理器的调用
    image.png
    每个XxConfig配置类都会对应一个BeanPostProcessor后置处理器,所以每个DubboConfigBindingBeanPostProcessor只处理其对应的bean。bind方法用来对XxConfig配置类,从properties文件中获取值,并设置到dubboConfig对象中。customize方法用来设置dubboConfig对象的name属性,设置为beanName
    c、bind
    org.apache.dubbo.config.spring.beans.factory.annotation.DubboConfigBindingBeanPostProcessor#bind
    通过DubboConfigBinder dubboConfigBinder进行绑定
    image.png
    ④、注册一个NamePropertyDefaultValueDubboConfigBeanCustomizer的bean
    EnableDubboConfigBinding

    2、DubboComponentScan

    扫描指定的包,会把添加了@Service注解的类添加到容器中。


    image.png

    这个DubboComponentScan注解import导入DubboComponentScanRegistrar类,DubboComponentScanRegistrar实现了ImportBeanDefinitionRegistrar


    image.png
    1、获取DubboComponentScan注解上的包路径,用来扫描该package下的类
    2、注册ServiceAnnotationBeanPostProcessor类型的Bean,用来处理@Service注解

    扫描包下添加了@Service注解的类,对于每个类都会生成一个BeanDefinition,对于每个对应的类都会注册一个ServiceBean,会把@Service注解包含的属性值、当前类的引用添加到ref中及其他信息都会添加到ServiceBean中。
    3、注册ReferenceAnnotationBeanPostProcessor,用来处理@Reference注解,进行属性填充

    @Service

    注册ServiceBean

    由于在注册ServiceAnnotationBeanPostProcessor中注册ServiceBean是比较核心的步骤,所以单独拎出来。
    1、registerServiceAnnotationBeanPostProcessor
    注册ServiceAnnotationBeanPostProcessor类型的Bean
    org.apache.dubbo.config.spring.context.annotation.DubboComponentScanRegistrar#registerServiceAnnotationBeanPostProcessor


    image.png

    生成一个beanClass是ServiceAnnotationBeanPostProcessor.class的beanDefinition,在构建这个beanDefinition时,把packagesToScan包路径作为构造方法参数传入到生成的Bean中。


    image.png
    会把传入的扫描包的路径赋值给ServiceAnnotationBeanPostProcessor#packagesToScan属性值
    2、ServiceAnnotationBeanPostProcessor
    ServiceAnnotationBeanPostProcessor类实现了BeanDefinitionRegistryPostProcessor,这里也是spring的扩展点之一。会在spring bean生成过程的生命周期中调用到postProcessBeanDefinitionRegistry方法
    org.apache.dubbo.config.spring.beans.factory.annotation.ServiceAnnotationBeanPostProcessor#
    postProcessBeanDefinitionRegistry
    image.png

    3、registerServiceBeans
    org.apache.dubbo.config.spring.beans.factory.annotation.ServiceAnnotationBeanPostProcessor#registerServiceBeans


    image.png
    ①、首先自定义一个扫描器DubboClassPathBeanDefinitionScanner
    ②、对这个扫描器进行属性设置及扫描规则添加。
    只对com.alibaba.dubbo.config.annotation.Service.class注解和org.apache.dubbo.config.
    annotation.Service.class注解过滤
    image.png
    image.png
    ③、对包扫描@Service的注解类得到的beanDefinition放入到beanDefinitionHolders集合中
    ④、对得到的每个beanDefinition进行注册ServiceBean
    4、registerServiceBean
    org.apache.dubbo.config.spring.beans.factory.annotation.ServiceAnnotationBeanPostProcessor#
    registerServiceBean
    image.png
    根据beanDefinitionHolder获取对应的类beanClass,获取注解service,获取当前类的注解信息属性值serviceAnnotationAttributes
    image.png

    注册ServiceBean,根据beanName和构建的serviceBeanDefinition。beanName是ServiceBean:org.apache.dubbo.demo.DemoService
    5、buildServiceBeanDefinition
    org.apache.dubbo.config.spring.beans.factory.annotation.ServiceAnnotationBeanPostProcessor#
    buildServiceBeanDefinition


    image.png
    生成一个类是ServiceBean对应的BeanDefinition,之后进行属性值处理
    image.png
    ①、把serviceAnnotation中的参数值赋值给ServiceBean的属性propertyValues
    ②、ref属性赋值为annotatedServiceBeanName, 对应的就是被@Service注解类对应的bean。
    ③、添加interface、parameters属性值
    ④、methods属性配置,则给ServiceBean对应的methods属性赋值
    ⑤、provider、monitor、application、module、registries、protocols属性添加
    6、onApplicationEvent
    ServiceBean注册之后,由于ServiceBean实现了ApplicationListener,所以在spring bean生命周期中,生成对应的Bean。便会调用ApplicationListener的实现类发布一个ContextRefreshedEvent事件。
    org.apache.dubbo.config.spring.ServiceBean#onApplicationEvent
    image.png
    调用到export();方法,就会进行服务注册(也叫dubbo服务导出),注册到注册中心。

    @Reference

    注册ReferenceAnnotationBeanPostProcessor

    org.apache.dubbo.config.spring.context.annotation.DubboComponentScanRegistrar#registerReferenceAnnotationBeanPostProcessor


    image.png

    beanName是referenceAnnotationBeanPostProcessor,beanClass是ReferenceAnnotationBeanPostProcessor的Bean。
    ReferenceAnnotationBeanPostProcessor继承了AnnotationInjectedBeanPostProcessor。
    AnnotationInjectedBeanPostProcessor是dubbo自定义的一个抽象后置处理器,继承了InstantiationAwareBeanPostProcessorAdapter,实现了MergedBeanDefinitionPostProcessor的spring后置处理器。这两个后置处理器会在spring bean的生命周期调用,分别调用postProcessMergedBeanDefinition和postProcessPropertyValues方法
    为什么仅仅说这两个方法,因为AnnotationInjectedBeanPostProcessor类在处理@Reference注解时重写了这两个方法。后置处理器重写也是spring扩展点之一,也是与spring整合的一个关键点。

    1、postProcessMergedBeanDefinition

    org.apache.dubbo.config.spring.beans.factory.annotation.AnnotationInjectedBeanPostProcessor#postProcessMergedBeanDefinition
    查找注入元数据InjectionMetadata包括字段注入和方法注入


    image.png

    在dubbo-demo测试代码中是这样引用的

    @Component("demoServiceComponent")
    public class DemoServiceComponent implements DemoService {
        @Reference
        private DemoService demoService; 
    }
    

    这个查找注入点的关键是如何查找到这些信息的,需要查看下findInjectionMetadata方法
    ①、findInjectionMetadata
    org.apache.dubbo.config.spring.beans.factory.annotation.AnnotationInjectedBeanPostProcessor#findInjectionMetadata


    image.png

    在injectionMetadataCache缓存中不存在当前类的注解信息,需要通过buildAnnotatedMetadata查找,并放入到injectionMetadataCache缓存中(结构是ConcurrentMap<String, AnnotationInjectedBeanPostProcessor.AnnotatedInjectionMetadata>)
    ②、buildAnnotatedMetadata


    image.png
    findFieldAnnotationMetadata用来查找filed字段上有@Reference注解
    findAnnotatedMethodMetadata用来查找method方法上有@Reference注解
    返回一个Dubbo自定义的AnnotatedInjectionMetadata,之后就可以使用这个类进行属性注入
    ③、findFieldAnnotationMetadata

    org.apache.dubbo.config.spring.beans.factory.annotation.AnnotationInjectedBeanPostProcessor#findFieldAnnotationMetadata


    image.png
    image.png
    这个注解类型annotationType是在创建ReferenceAnnotationBeanPostProcessor时通过构造方法传入
    image.png
    赋值给AnnotationInjectedBeanPostProcessor的annotationTypes
    image.png
    所以这个方法就是寻找在当前类中添加了@Reference注解的字段,如果是静态的static则不会添加到elements中
    ④、findAnnotatedMethodMetadata
    把set方法的参数(找到set方法所对应的属性)添加到elements中
    image.png
    image.png
    ⑤、AnnotationInjectedBeanPostProcessor.AnnotatedInjectionMetadata
    返回注入类型AnnotatedInjectionMetadata,是一个实现了InjectionMetadata的内部类,包含需要注入的字段集合fieldElements和方法集合methodElements。这两个集合的类型是实现了InjectionMetadata.InjectedElement的内部类AnnotationInjectedBeanPostProcessor.AnnotatedFieldElement和AnnotatedMethodElement
    image.png
    2、postProcessPropertyValues
    image.png

    这时injectionMetadataCache已经存在当前bean的属性,之后调用inject进行注入。便会调用AnnotatedFieldElement和AnnotatedMethodElement的inject方法
    1、AnnotatedFieldElement#inject
    org.apache.dubbo.config.spring.beans.factory.annotation.AnnotationInjectedBeanPostProcessor.
    AnnotatedFieldElement#inject


    image.png

    2、getInjectedObject
    org.apache.dubbo.config.spring.beans.factory.annotation.AnnotationInjectedBeanPostProcessor#getInjectedObject


    image.png
    哪个Service应用了哪个类型的服务,通过什么方式引入的
    cacheKey属性名不一样的时候,cacheKey不一样,导致不能缓存, 在一个Service中@Reference两次同一个服务缓存不到
    3、doGetInjectedBean
    org.apache.dubbo.config.spring.beans.factory.annotation.ReferenceAnnotationBeanPostProcessor#
    doGetInjectedBean
    image.png

    ①、referencedBeanName:表示得到引入服务的beanName,示例代码引入的是ServiceBean:org.apache.dubbo.demo.DemoService
    这个值也可以判断引用的这个服务是不是我自己导出的。attributes里存的是@Reference注解中的所配置的属性与值,injectedType表示引入的是哪个服务接口
    ②、referenceBeanName:@Reference org.apache.dubbo.demo.DemoServiceorg.apache.dubbo.demo.DemoService
    表示,要的根据@Reference注解来生成一个RefrenceBean,对应的beanName


    image.png
    ③、生成ReferenceBean对象,并放到referenceBeanCache缓存
    ④、把referenceBean注册到Spring容器中去
    ⑤、缓存需要注入的引用对象
    ⑥、返回代理对象
    4、buildReferenceBeanIfAbsent
    org.apache.dubbo.config.spring.beans.factory.annotation.ReferenceAnnotationBeanPostProcessor#
    buildReferenceBeanIfAbsent
    生成了一个ReferenceBean对象,attributes是@Reference注解的参数值
    image.png
    5、build
    org.apache.dubbo.config.spring.beans.factory.annotation.AnnotatedInterfaceConfigBeanBuilder#build
    image.png
    ①、checkDependencies()空方法
    ②、创建一个ReferenceBean对象
    org.apache.dubbo.config.spring.beans.factory.annotation.ReferenceBeanBuilder#doBuild
    image.png

    ③、给ReferenceBean对象的属性赋值
    org.apache.dubbo.config.spring.beans.factory.annotation.AnnotatedInterfaceConfigBeanBuilder#
    configureBean


    image.png
    attributes注解上的属性值、注解上registry的值、注解上的monitor值、注解上的application、注解上的module值
    org.apache.dubbo.config.spring.beans.factory.annotation.AnnotatedInterfaceConfigBeanBuilder#
    configureRegistryConfigs
    解析@Refrence注解中配置的registry属性、获得注册中心对应的RegistryConfig对象
    image.png
    org.apache.dubbo.config.spring.beans.factory.annotation.ReferenceBeanBuilder#resolveRegistryConfigBeanNames
    image.png
    org.apache.dubbo.config.spring.beans.factory.annotation.ReferenceBeanBuilder#postConfigureBean
    设置applicationContext、interfaceName、consumer、methods属性,并调用ReferenceBean对象的afterPropertiesSet方法
    image.png
    ④、afterPropertiesSet
    org.apache.dubbo.config.spring.ReferenceBean#afterPropertiesSet
    这个方法还是在给ReferenceBean对象的属性赋值、如果@Reference注解中没有配置consumer属性(getConsumer() == null),则会从Spring容器中寻找ConsumerConfig类型的Bean, 例如可以通过@Bean定义了一个ConsumerConfig的Bean,有可能存在多个ConsumerConfig类型的Bean,遍历这些Bean,取第一个没有配置default或者default为true的Bean作为consumer的值
    image.png
    6、registerReferenceBean
    image.png
    image.png
    beanName是@Reference org.apache.dubbo.demo.DemoService的Bean,如果本地存在则会使用本地服务。如果是本地提供的一个服务,那么@Reference org.apache.dubbo.demo.DemoService的别名是demoService,不需要是ServiceBean的名字
    7、cacheInjectedReferenceBean
    org.apache.dubbo.config.spring.beans.factory.annotation.ReferenceAnnotationBeanPostProcessor#
    cacheInjectedReferenceBean
    image.png
    8、getOrCreateProxy
    org.apache.dubbo.config.spring.beans.factory.annotation.ReferenceAnnotationBeanPostProcessor#
    getOrCreateProxy
    image.png
    org.apache.dubbo.config.ReferenceConfig#get
    返回的ref便是经过Invoke代理的对象,这里涉及到dubbo的服务引入。
    image.png
    9、最终得到的代理对象,便可以通过field.set设置
    image.png
    image.png

    总结:

    Dubbo与Spring整合用到了Spring的多个扩展点。这些扩展点的目的就是把dubbo自定义的注解(@Service和@Reference)注册到spring容器,然后实现服务导入(注册)和服务引用。要了解这些扩展点需要对spring有一定的了解,并了解其执行时机。
    扩展点:实现了ImportBeanDefinitionRegistrar、BeanDefinitionRegistryPostProcessor、BeanPostProcessor后置处理器

    相关文章

      网友评论

        本文标题:Dubbo与Spring整合源码分析

        本文链接:https://www.haomeiwen.com/subject/ovtglktx.html