Dubbo与Spring整合源码分析

通过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)
②、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整合源码分析)