通過(guò)EnableDubbo和PropertySource開(kāi)啟了dubbo
PropertySource是spring的注解棍掐,用來(lái)指定配置文件路徑
EnableDubbo
@EnableDubboConfig注解用來(lái)將properties配置文件中的配置項(xiàng)轉(zhuǎn)化為相對(duì)應(yīng)的Bean
@DubboComponentScan注解用來(lái)掃描服務(wù)提供者和引用者(@Service)
1厌处、EnableDubboConfig
1堰汉、導(dǎo)入DubboConfigConfigurationRegistrar類調(diào)用registerBeanDefinitions
EnableDubboConfig注解中import導(dǎo)入DubboConfigConfigurationRegistrar類
DubboConfigConfigurationRegistrar實(shí)現(xiàn)了ImportBeanDefinitionRegistrar類,這個(gè)類是Spring的擴(kuò)展點(diǎn)之一拾枣,用來(lái)向spring容器中注冊(cè)Bean亏娜,某個(gè)時(shí)機(jī)會(huì)調(diào)用到registerBeanDefinitions()方法
org.apache.dubbo.config.spring.context.annotation.DubboConfigConfigurationRegistrar#registerBeanDefinitions
對(duì)于添加了EnableDubboConfig注解(添加了EnableDubbo注解)的類的元數(shù)據(jù)信息职辅,便會(huì)得到EnableDubboConfig注解的屬性值,根據(jù)屬性值鍵值對(duì)可以獲取multiple的屬性值唬滑,默認(rèn)multiple=true告唆。用來(lái)決定是注冊(cè)DubboConfigConfiguration.Single的Bean還是注冊(cè)DubboConfigConfiguration.Multiple.class類型的Bean
2、multiple=true的意義
以protocol為例晶密,multiple=true的意義表示protocols有多種
3擒悬、Single和Multiple
DubboConfigConfiguration.Single
DubboConfigConfiguration.Multiple
DubboConfigConfiguration.Single有兩個(gè)注解:@EnableDubboConfigBindings和@EnableDubboConfigBinding
Single和Multiple的唯一區(qū)別就是Multiple=true。
4惹挟、EnableDubboConfigBindings
導(dǎo)入DubboConfigBindingsRegistrar類
DubboConfigBindingsRegistrar實(shí)現(xiàn)了ImportBeanDefinitionRegistrar
這個(gè)registerBeanDefinitions方法就是獲取注解信息中@EnableDubboConfigBindings包含的@EnableDubboConfigBinding注解
,然后進(jìn)行遍歷注冊(cè)調(diào)用DubboConfigBindingRegistrar的registerBeanDefinitions方法
5连锯、registerBeanDefinitions
org.apache.dubbo.config.spring.context.annotation.DubboConfigBindingRegistrar#
registerBeanDefinitions
以dubbo.application配置為例归苍,把前綴是dubbo.application的配置與type的class類型是org.apache.dubbo.config.ApplicationConfig注冊(cè)一個(gè)XxxConfig配置Bean
6、registerDubboConfigBeans
org.apache.dubbo.config.spring.context.annotation.DubboConfigBindingRegistrar#registerDubboConfigBeans
①运怖、根據(jù)multiple的值拼弃,獲取beanName
如果multiple為false,則看有沒(méi)有配置id屬性摇展,如果沒(méi)有配置則自動(dòng)生成一個(gè)
org.apache.dubbo.config.spring.context.annotation.DubboConfigBindingRegistrar#
resolveMultipleBeanNames
②吻氧、如果配置有多個(gè)(multiple=true)則會(huì)為每個(gè)beanName都會(huì)注冊(cè)一個(gè)BeanDefinition的配置類,這些配置了都實(shí)現(xiàn)了AbstractConfig
③、如果配置有多個(gè)(multiple=true)則為每個(gè)bean注冊(cè)一個(gè)類型是DubboConfigBindingBeanPostProcessor的后置處理器
a盯孙、registerDubboConfigBindingBeanPostProcessor
org.apache.dubbo.config.spring.context.annotation.DubboConfigBindingRegistrar#
registerDubboConfigBindingBeanPostProcessor
DubboConfigBindingBeanPostProcessor實(shí)現(xiàn)了BeanPostProcessor, ApplicationContextAware, InitializingBean , BeanDefinitionRegistryPostProcessor
b鲁森、postProcessBeforeInitialization
org.apache.dubbo.config.spring.beans.factory.annotation.DubboConfigBindingBeanPostProcessor#
postProcessBeforeInitialization
這里是spring后置處理器的調(diào)用
每個(gè)XxConfig配置類都會(huì)對(duì)應(yīng)一個(gè)BeanPostProcessor后置處理器,所以每個(gè)DubboConfigBindingBeanPostProcessor只處理其對(duì)應(yīng)的bean振惰。bind方法用來(lái)對(duì)XxConfig配置類歌溉,從properties文件中獲取值,并設(shè)置到dubboConfig對(duì)象中骑晶。customize方法用來(lái)設(shè)置dubboConfig對(duì)象的name屬性痛垛,設(shè)置為beanName
c、bind
org.apache.dubbo.config.spring.beans.factory.annotation.DubboConfigBindingBeanPostProcessor#bind
通過(guò)DubboConfigBinder dubboConfigBinder進(jìn)行綁定
④桶蛔、注冊(cè)一個(gè)NamePropertyDefaultValueDubboConfigBeanCustomizer的bean
EnableDubboConfigBinding
2匙头、DubboComponentScan
掃描指定的包,會(huì)把添加了@Service注解的類添加到容器中仔雷。
這個(gè)DubboComponentScan注解import導(dǎo)入DubboComponentScanRegistrar類蹂析,DubboComponentScanRegistrar實(shí)現(xiàn)了ImportBeanDefinitionRegistrar
1、獲取DubboComponentScan注解上的包路徑朽寞,用來(lái)掃描該package下的類
2识窿、注冊(cè)ServiceAnnotationBeanPostProcessor類型的Bean,用來(lái)處理@Service注解
掃描包下添加了@Service注解的類脑融,對(duì)于每個(gè)類都會(huì)生成一個(gè)BeanDefinition喻频,對(duì)于每個(gè)對(duì)應(yīng)的類都會(huì)注冊(cè)一個(gè)ServiceBean,會(huì)把@Service注解包含的屬性值肘迎、當(dāng)前類的引用添加到ref中及其他信息都會(huì)添加到ServiceBean中甥温。
3、注冊(cè)ReferenceAnnotationBeanPostProcessor妓布,用來(lái)處理@Reference注解姻蚓,進(jìn)行屬性填充
@Service
注冊(cè)ServiceBean
由于在注冊(cè)ServiceAnnotationBeanPostProcessor中注冊(cè)ServiceBean是比較核心的步驟,所以單獨(dú)拎出來(lái)匣沼。
1狰挡、registerServiceAnnotationBeanPostProcessor
注冊(cè)ServiceAnnotationBeanPostProcessor類型的Bean
org.apache.dubbo.config.spring.context.annotation.DubboComponentScanRegistrar#registerServiceAnnotationBeanPostProcessor
生成一個(gè)beanClass是ServiceAnnotationBeanPostProcessor.class的beanDefinition,在構(gòu)建這個(gè)beanDefinition時(shí)释涛,把packagesToScan包路徑作為構(gòu)造方法參數(shù)傳入到生成的Bean中加叁。
會(huì)把傳入的掃描包的路徑賦值給ServiceAnnotationBeanPostProcessor#packagesToScan屬性值
2、ServiceAnnotationBeanPostProcessor
ServiceAnnotationBeanPostProcessor類實(shí)現(xiàn)了BeanDefinitionRegistryPostProcessor唇撬,這里也是spring的擴(kuò)展點(diǎn)之一它匕。會(huì)在spring bean生成過(guò)程的生命周期中調(diào)用到postProcessBeanDefinitionRegistry方法
org.apache.dubbo.config.spring.beans.factory.annotation.ServiceAnnotationBeanPostProcessor#
postProcessBeanDefinitionRegistry
3、registerServiceBeans
org.apache.dubbo.config.spring.beans.factory.annotation.ServiceAnnotationBeanPostProcessor#registerServiceBeans
①窖认、首先自定義一個(gè)掃描器DubboClassPathBeanDefinitionScanner
②豫柬、對(duì)這個(gè)掃描器進(jìn)行屬性設(shè)置及掃描規(guī)則添加告希。
只對(duì)com.alibaba.dubbo.config.annotation.Service.class注解和org.apache.dubbo.config.
annotation.Service.class注解過(guò)濾
③、對(duì)包掃描@Service的注解類得到的beanDefinition放入到beanDefinitionHolders集合中
④烧给、對(duì)得到的每個(gè)beanDefinition進(jìn)行注冊(cè)ServiceBean
4燕偶、registerServiceBean
org.apache.dubbo.config.spring.beans.factory.annotation.ServiceAnnotationBeanPostProcessor#
registerServiceBean
根據(jù)beanDefinitionHolder獲取對(duì)應(yīng)的類beanClass,獲取注解service创夜,獲取當(dāng)前類的注解信息屬性值serviceAnnotationAttributes
注冊(cè)ServiceBean杭跪,根據(jù)beanName和構(gòu)建的serviceBeanDefinition。beanName是ServiceBean:org.apache.dubbo.demo.DemoService
5驰吓、buildServiceBeanDefinition
org.apache.dubbo.config.spring.beans.factory.annotation.ServiceAnnotationBeanPostProcessor#
buildServiceBeanDefinition
生成一個(gè)類是ServiceBean對(duì)應(yīng)的BeanDefinition,之后進(jìn)行屬性值處理
①系奉、把serviceAnnotation中的參數(shù)值賦值給ServiceBean的屬性propertyValues
②檬贰、ref屬性賦值為annotatedServiceBeanName, 對(duì)應(yīng)的就是被@Service注解類對(duì)應(yīng)的bean。
③缺亮、添加interface翁涤、parameters屬性值
④、methods屬性配置萌踱,則給ServiceBean對(duì)應(yīng)的methods屬性賦值
⑤葵礼、provider、monitor并鸵、application鸳粉、module、registries园担、protocols屬性添加
6届谈、onApplicationEvent
ServiceBean注冊(cè)之后,由于ServiceBean實(shí)現(xiàn)了ApplicationListener弯汰,所以在spring bean生命周期中艰山,生成對(duì)應(yīng)的Bean。便會(huì)調(diào)用ApplicationListener的實(shí)現(xiàn)類發(fā)布一個(gè)ContextRefreshedEvent事件咏闪。
org.apache.dubbo.config.spring.ServiceBean#onApplicationEvent
調(diào)用到export();方法曙搬,就會(huì)進(jìn)行服務(wù)注冊(cè)(也叫dubbo服務(wù)導(dǎo)出),注冊(cè)到注冊(cè)中心鸽嫂。
@Reference
注冊(cè)ReferenceAnnotationBeanPostProcessor
org.apache.dubbo.config.spring.context.annotation.DubboComponentScanRegistrar#registerReferenceAnnotationBeanPostProcessor
beanName是referenceAnnotationBeanPostProcessor纵装,beanClass是ReferenceAnnotationBeanPostProcessor的Bean。
ReferenceAnnotationBeanPostProcessor繼承了AnnotationInjectedBeanPostProcessor溪胶。
AnnotationInjectedBeanPostProcessor是dubbo自定義的一個(gè)抽象后置處理器搂擦,繼承了InstantiationAwareBeanPostProcessorAdapter,實(shí)現(xiàn)了MergedBeanDefinitionPostProcessor的spring后置處理器哗脖。這兩個(gè)后置處理器會(huì)在spring bean的生命周期調(diào)用瀑踢,分別調(diào)用postProcessMergedBeanDefinition和postProcessPropertyValues方法
為什么僅僅說(shuō)這兩個(gè)方法扳还,因?yàn)锳nnotationInjectedBeanPostProcessor類在處理@Reference注解時(shí)重寫(xiě)了這兩個(gè)方法。后置處理器重寫(xiě)也是spring擴(kuò)展點(diǎn)之一橱夭,也是與spring整合的一個(gè)關(guān)鍵點(diǎn)氨距。
1、postProcessMergedBeanDefinition
org.apache.dubbo.config.spring.beans.factory.annotation.AnnotationInjectedBeanPostProcessor#postProcessMergedBeanDefinition
查找注入元數(shù)據(jù)InjectionMetadata包括字段注入和方法注入
在dubbo-demo測(cè)試代碼中是這樣引用的
@Component("demoServiceComponent")
public class DemoServiceComponent implements DemoService {
@Reference
private DemoService demoService;
}
這個(gè)查找注入點(diǎn)的關(guān)鍵是如何查找到這些信息的棘劣,需要查看下findInjectionMetadata方法
①俏让、findInjectionMetadata
org.apache.dubbo.config.spring.beans.factory.annotation.AnnotationInjectedBeanPostProcessor#findInjectionMetadata
在injectionMetadataCache緩存中不存在當(dāng)前類的注解信息,需要通過(guò)buildAnnotatedMetadata查找茬暇,并放入到injectionMetadataCache緩存中(結(jié)構(gòu)是ConcurrentMap<String, AnnotationInjectedBeanPostProcessor.AnnotatedInjectionMetadata>)
②首昔、buildAnnotatedMetadata
findFieldAnnotationMetadata用來(lái)查找filed字段上有@Reference注解
findAnnotatedMethodMetadata用來(lái)查找method方法上有@Reference注解
返回一個(gè)Dubbo自定義的AnnotatedInjectionMetadata,之后就可以使用這個(gè)類進(jìn)行屬性注入
③、findFieldAnnotationMetadata
org.apache.dubbo.config.spring.beans.factory.annotation.AnnotationInjectedBeanPostProcessor#findFieldAnnotationMetadata
這個(gè)注解類型annotationType是在創(chuàng)建ReferenceAnnotationBeanPostProcessor時(shí)通過(guò)構(gòu)造方法傳入
賦值給AnnotationInjectedBeanPostProcessor的annotationTypes
所以這個(gè)方法就是尋找在當(dāng)前類中添加了@Reference注解的字段,如果是靜態(tài)的static則不會(huì)添加到elements中
④尖坤、findAnnotatedMethodMetadata
把set方法的參數(shù)(找到set方法所對(duì)應(yīng)的屬性)添加到elements中
⑤评凝、AnnotationInjectedBeanPostProcessor.AnnotatedInjectionMetadata
返回注入類型AnnotatedInjectionMetadata,是一個(gè)實(shí)現(xiàn)了InjectionMetadata的內(nèi)部類,包含需要注入的字段集合fieldElements和方法集合methodElements。這兩個(gè)集合的類型是實(shí)現(xiàn)了InjectionMetadata.InjectedElement的內(nèi)部類AnnotationInjectedBeanPostProcessor.AnnotatedFieldElement和AnnotatedMethodElement
2、postProcessPropertyValues
這時(shí)injectionMetadataCache已經(jīng)存在當(dāng)前bean的屬性竣蹦,之后調(diào)用inject進(jìn)行注入。便會(huì)調(diào)用AnnotatedFieldElement和AnnotatedMethodElement的inject方法
1沧奴、AnnotatedFieldElement#inject
org.apache.dubbo.config.spring.beans.factory.annotation.AnnotationInjectedBeanPostProcessor.
AnnotatedFieldElement#inject
2痘括、getInjectedObject
org.apache.dubbo.config.spring.beans.factory.annotation.AnnotationInjectedBeanPostProcessor#getInjectedObject
哪個(gè)Service應(yīng)用了哪個(gè)類型的服務(wù),通過(guò)什么方式引入的
cacheKey屬性名不一樣的時(shí)候扼仲,cacheKey不一樣远寸,導(dǎo)致不能緩存, 在一個(gè)Service中@Reference兩次同一個(gè)服務(wù)緩存不到
3屠凶、doGetInjectedBean
org.apache.dubbo.config.spring.beans.factory.annotation.ReferenceAnnotationBeanPostProcessor#
doGetInjectedBean
①驰后、referencedBeanName:表示得到引入服務(wù)的beanName,示例代碼引入的是ServiceBean:org.apache.dubbo.demo.DemoService
這個(gè)值也可以判斷引用的這個(gè)服務(wù)是不是我自己導(dǎo)出的矗愧。attributes里存的是@Reference注解中的所配置的屬性與值灶芝,injectedType表示引入的是哪個(gè)服務(wù)接口
②、referenceBeanName:@Reference org.apache.dubbo.demo.DemoServiceorg.apache.dubbo.demo.DemoService
表示唉韭,要的根據(jù)@Reference注解來(lái)生成一個(gè)RefrenceBean夜涕,對(duì)應(yīng)的beanName
③、生成ReferenceBean對(duì)象属愤,并放到referenceBeanCache緩存
④女器、把referenceBean注冊(cè)到Spring容器中去
⑤、緩存需要注入的引用對(duì)象
⑥住诸、返回代理對(duì)象
4驾胆、buildReferenceBeanIfAbsent
org.apache.dubbo.config.spring.beans.factory.annotation.ReferenceAnnotationBeanPostProcessor#
buildReferenceBeanIfAbsent
生成了一個(gè)ReferenceBean對(duì)象涣澡,attributes是@Reference注解的參數(shù)值
5、build
org.apache.dubbo.config.spring.beans.factory.annotation.AnnotatedInterfaceConfigBeanBuilder#build
①丧诺、checkDependencies()空方法
②入桂、創(chuàng)建一個(gè)ReferenceBean對(duì)象
org.apache.dubbo.config.spring.beans.factory.annotation.ReferenceBeanBuilder#doBuild
③、給ReferenceBean對(duì)象的屬性賦值
org.apache.dubbo.config.spring.beans.factory.annotation.AnnotatedInterfaceConfigBeanBuilder#
configureBean
attributes注解上的屬性值驳阎、注解上registry的值抗愁、注解上的monitor值、注解上的application呵晚、注解上的module值
org.apache.dubbo.config.spring.beans.factory.annotation.AnnotatedInterfaceConfigBeanBuilder#
configureRegistryConfigs
解析@Refrence注解中配置的registry屬性蜘腌、獲得注冊(cè)中心對(duì)應(yīng)的RegistryConfig對(duì)象
org.apache.dubbo.config.spring.beans.factory.annotation.ReferenceBeanBuilder#resolveRegistryConfigBeanNames
org.apache.dubbo.config.spring.beans.factory.annotation.ReferenceBeanBuilder#postConfigureBean
設(shè)置applicationContext、interfaceName饵隙、consumer逢捺、methods屬性,并調(diào)用ReferenceBean對(duì)象的afterPropertiesSet方法
④癞季、afterPropertiesSet
org.apache.dubbo.config.spring.ReferenceBean#afterPropertiesSet
這個(gè)方法還是在給ReferenceBean對(duì)象的屬性賦值、如果@Reference注解中沒(méi)有配置consumer屬性(getConsumer() == null)倘潜,則會(huì)從Spring容器中尋找ConsumerConfig類型的Bean, 例如可以通過(guò)@Bean定義了一個(gè)ConsumerConfig的Bean绷柒,有可能存在多個(gè)ConsumerConfig類型的Bean,遍歷這些Bean涮因,取第一個(gè)沒(méi)有配置default或者default為true的Bean作為consumer的值
6废睦、registerReferenceBean
beanName是@Reference org.apache.dubbo.demo.DemoService的Bean,如果本地存在則會(huì)使用本地服務(wù)养泡。如果是本地提供的一個(gè)服務(wù)嗜湃,那么@Reference org.apache.dubbo.demo.DemoService的別名是demoService,不需要是ServiceBean的名字
7澜掩、cacheInjectedReferenceBean
org.apache.dubbo.config.spring.beans.factory.annotation.ReferenceAnnotationBeanPostProcessor#
cacheInjectedReferenceBean
8购披、getOrCreateProxy
org.apache.dubbo.config.spring.beans.factory.annotation.ReferenceAnnotationBeanPostProcessor#
getOrCreateProxy
org.apache.dubbo.config.ReferenceConfig#get
返回的ref便是經(jīng)過(guò)Invoke代理的對(duì)象,這里涉及到dubbo的服務(wù)引入肩榕。
9刚陡、最終得到的代理對(duì)象,便可以通過(guò)field.set設(shè)置
總結(jié):
Dubbo與Spring整合用到了Spring的多個(gè)擴(kuò)展點(diǎn)株汉。這些擴(kuò)展點(diǎn)的目的就是把dubbo自定義的注解(@Service和@Reference)注冊(cè)到spring容器筐乳,然后實(shí)現(xiàn)服務(wù)導(dǎo)入(注冊(cè))和服務(wù)引用。要了解這些擴(kuò)展點(diǎn)需要對(duì)spring有一定的了解乔妈,并了解其執(zhí)行時(shí)機(jī)蝙云。
擴(kuò)展點(diǎn):實(shí)現(xiàn)了ImportBeanDefinitionRegistrar、BeanDefinitionRegistryPostProcessor路召、BeanPostProcessor后置處理器