通过EnableDubbo和PropertySource开启了dubbo
PropertySource是spring的注解,用来指定配置文件路径
EnableDubbo
@EnableDubboConfig注解用来将properties配置文件中的配置项转化为相对应的Bean
@DubboComponentScan注解用来扫描服务提供者和引用者(@Service)
1、EnableDubboConfig
1、导入DubboConfigConfigurationRegistrar类调用registerBeanDefinitions
EnableDubboConfig注解中import导入DubboConfigConfigurationRegistrar类
DubboConfigConfigurationRegistrar实现了ImportBeanDefinitionRegistrar类,这个类是Spring的扩展点之一,用来向spring容器中注册Bean,某个时机会调用到registerBeanDefinitions()方法
org.apache.dubbo.config.spring.context.annotation.DubboConfigConfigurationRegistrar#registerBeanDefinitions
对于添加了EnableDubboConfig注解(添加了EnableDubbo注解)的类的元数据信息,便会得到EnableDubboConfig注解的属性值,根据属性值键值对可以获取multiple的属性值,默认multiple=true。用来决定是注册DubboConfigConfiguration.Single的Bean还是注册DubboConfigConfiguration.Multiple.class类型的Bean
2、multiple=true的意义
以protocol为例,multiple=true的意义表示protocols有多种
3、Single和Multiple
DubboConfigConfiguration.Single
DubboConfigConfiguration.Multiple
DubboConfigConfiguration.Single有两个注解:@EnableDubboConfigBindings和@EnableDubboConfigBinding
Single和Multiple的唯一区别就是Multiple=true。
4、EnableDubboConfigBindings
导入DubboConfigBindingsRegistrar类
DubboConfigBindingsRegistrar实现了ImportBeanDefinitionRegistrar
这个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
6、registerDubboConfigBeans
org.apache.dubbo.config.spring.context.annotation.DubboConfigBindingRegistrar#registerDubboConfigBeans
①、根据multiple的值,获取beanName
如果multiple为false,则看有没有配置id属性,如果没有配置则自动生成一个
org.apache.dubbo.config.spring.context.annotation.DubboConfigBindingRegistrar#
resolveMultipleBeanNames
②、如果配置有多个(multiple=true)则会为每个beanName都会注册一个BeanDefinition的配置类,这些配置了都实现了AbstractConfig
③、如果配置有多个(multiple=true)则为每个bean注册一个类型是DubboConfigBindingBeanPostProcessor的后置处理器
a、registerDubboConfigBindingBeanPostProcessor
org.apache.dubbo.config.spring.context.annotation.DubboConfigBindingRegistrar#
registerDubboConfigBindingBeanPostProcessor
DubboConfigBindingBeanPostProcessor实现了BeanPostProcessor, ApplicationContextAware, InitializingBean , BeanDefinitionRegistryPostProcessor
b、postProcessBeforeInitialization
org.apache.dubbo.config.spring.beans.factory.annotation.DubboConfigBindingBeanPostProcessor#
postProcessBeforeInitialization
这里是spring后置处理器的调用
每个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进行绑定
④、注册一个NamePropertyDefaultValueDubboConfigBeanCustomizer的bean
EnableDubboConfigBinding
2、DubboComponentScan
扫描指定的包,会把添加了@Service注解的类添加到容器中。
这个DubboComponentScan注解import导入DubboComponentScanRegistrar类,DubboComponentScanRegistrar实现了ImportBeanDefinitionRegistrar
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
生成一个beanClass是ServiceAnnotationBeanPostProcessor.class的beanDefinition,在构建这个beanDefinition时,把packagesToScan包路径作为构造方法参数传入到生成的Bean中。
会把传入的扫描包的路径赋值给ServiceAnnotationBeanPostProcessor#packagesToScan属性值
2、ServiceAnnotationBeanPostProcessor
ServiceAnnotationBeanPostProcessor类实现了BeanDefinitionRegistryPostProcessor,这里也是spring的扩展点之一。会在spring bean生成过程的生命周期中调用到postProcessBeanDefinitionRegistry方法
org.apache.dubbo.config.spring.beans.factory.annotation.ServiceAnnotationBeanPostProcessor#
postProcessBeanDefinitionRegistry
3、registerServiceBeans
org.apache.dubbo.config.spring.beans.factory.annotation.ServiceAnnotationBeanPostProcessor#registerServiceBeans
①、首先自定义一个扫描器DubboClassPathBeanDefinitionScanner
②、对这个扫描器进行属性设置及扫描规则添加。
只对com.alibaba.dubbo.config.annotation.Service.class注解和org.apache.dubbo.config.
annotation.Service.class注解过滤
③、对包扫描@Service的注解类得到的beanDefinition放入到beanDefinitionHolders集合中
④、对得到的每个beanDefinition进行注册ServiceBean
4、registerServiceBean
org.apache.dubbo.config.spring.beans.factory.annotation.ServiceAnnotationBeanPostProcessor#
registerServiceBean
根据beanDefinitionHolder获取对应的类beanClass,获取注解service,获取当前类的注解信息属性值serviceAnnotationAttributes
注册ServiceBean,根据beanName和构建的serviceBeanDefinition。beanName是ServiceBean:org.apache.dubbo.demo.DemoService
5、buildServiceBeanDefinition
org.apache.dubbo.config.spring.beans.factory.annotation.ServiceAnnotationBeanPostProcessor#
buildServiceBeanDefinition
生成一个类是ServiceBean对应的BeanDefinition,之后进行属性值处理
①、把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
调用到export();方法,就会进行服务注册(也叫dubbo服务导出),注册到注册中心。
@Reference
注册ReferenceAnnotationBeanPostProcessor
org.apache.dubbo.config.spring.context.annotation.DubboComponentScanRegistrar#registerReferenceAnnotationBeanPostProcessor
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包括字段注入和方法注入
在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
在injectionMetadataCache缓存中不存在当前类的注解信息,需要通过buildAnnotatedMetadata查找,并放入到injectionMetadataCache缓存中(结构是ConcurrentMap<String, AnnotationInjectedBeanPostProcessor.AnnotatedInjectionMetadata>)
②、buildAnnotatedMetadata
findFieldAnnotationMetadata用来查找filed字段上有@Reference注解
findAnnotatedMethodMetadata用来查找method方法上有@Reference注解
返回一个Dubbo自定义的AnnotatedInjectionMetadata,之后就可以使用这个类进行属性注入
③、findFieldAnnotationMetadata
org.apache.dubbo.config.spring.beans.factory.annotation.AnnotationInjectedBeanPostProcessor#findFieldAnnotationMetadata
这个注解类型annotationType是在创建ReferenceAnnotationBeanPostProcessor时通过构造方法传入
赋值给AnnotationInjectedBeanPostProcessor的annotationTypes
所以这个方法就是寻找在当前类中添加了@Reference注解的字段,如果是静态的static则不会添加到elements中
④、findAnnotatedMethodMetadata
把set方法的参数(找到set方法所对应的属性)添加到elements中
⑤、AnnotationInjectedBeanPostProcessor.AnnotatedInjectionMetadata
返回注入类型AnnotatedInjectionMetadata,是一个实现了InjectionMetadata的内部类,包含需要注入的字段集合fieldElements和方法集合methodElements。这两个集合的类型是实现了InjectionMetadata.InjectedElement的内部类AnnotationInjectedBeanPostProcessor.AnnotatedFieldElement和AnnotatedMethodElement
2、postProcessPropertyValues
这时injectionMetadataCache已经存在当前bean的属性,之后调用inject进行注入。便会调用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
哪个Service应用了哪个类型的服务,通过什么方式引入的
cacheKey属性名不一样的时候,cacheKey不一样,导致不能缓存, 在一个Service中@Reference两次同一个服务缓存不到
3、doGetInjectedBean
org.apache.dubbo.config.spring.beans.factory.annotation.ReferenceAnnotationBeanPostProcessor#
doGetInjectedBean
①、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
③、生成ReferenceBean对象,并放到referenceBeanCache缓存
④、把referenceBean注册到Spring容器中去
⑤、缓存需要注入的引用对象
⑥、返回代理对象
4、buildReferenceBeanIfAbsent
org.apache.dubbo.config.spring.beans.factory.annotation.ReferenceAnnotationBeanPostProcessor#
buildReferenceBeanIfAbsent
生成了一个ReferenceBean对象,attributes是@Reference注解的参数值
5、build
org.apache.dubbo.config.spring.beans.factory.annotation.AnnotatedInterfaceConfigBeanBuilder#build
①、checkDependencies()空方法
②、创建一个ReferenceBean对象
org.apache.dubbo.config.spring.beans.factory.annotation.ReferenceBeanBuilder#doBuild
③、给ReferenceBean对象的属性赋值
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属性、获得注册中心对应的RegistryConfig对象
org.apache.dubbo.config.spring.beans.factory.annotation.ReferenceBeanBuilder#resolveRegistryConfigBeanNames
org.apache.dubbo.config.spring.beans.factory.annotation.ReferenceBeanBuilder#postConfigureBean
设置applicationContext、interfaceName、consumer、methods属性,并调用ReferenceBean对象的afterPropertiesSet方法
④、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的值
6、registerReferenceBean
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
8、getOrCreateProxy
org.apache.dubbo.config.spring.beans.factory.annotation.ReferenceAnnotationBeanPostProcessor#
getOrCreateProxy
org.apache.dubbo.config.ReferenceConfig#get
返回的ref便是经过Invoke代理的对象,这里涉及到dubbo的服务引入。
9、最终得到的代理对象,便可以通过field.set设置
总结:
Dubbo与Spring整合用到了Spring的多个扩展点。这些扩展点的目的就是把dubbo自定义的注解(@Service和@Reference)注册到spring容器,然后实现服务导入(注册)和服务引用。要了解这些扩展点需要对spring有一定的了解,并了解其执行时机。
扩展点:实现了ImportBeanDefinitionRegistrar、BeanDefinitionRegistryPostProcessor、BeanPostProcessor后置处理器