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<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后置处理器

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
禁止转载,如需转载请通过简信或评论联系作者。
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,271评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,275评论 2 380
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,151评论 0 336
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,550评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,553评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,559评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,924评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,580评论 0 257
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,826评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,578评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,661评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,363评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,940评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,926评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,156评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,872评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,391评论 2 342