
SpringCloud Alibaba系列——5Dubbo整合spring(下)
作者 | 一起撸Java
来源 |今日头条
学习目标
本文主要讲解Dubbo基于注解的方式集成spring
第2章 注解方式整合
注解方式已经是现在的主流了,例如springboot现在都是零xml配置了,只要通过少量的配置就可以完成框架的引用。
2.1 案例
生产者
配置类
dubbo-provider.properties配置
服务暴露
启动
2.2 优势
可以看到,只需要在需要暴露的服务上面加上一个@DubboService注解就可以完成服务的暴露了,配置量非常少,但是这种方式也有一定的侵入性。
2.3 源码分析
2.3.1 @EnableDubbo
@EnableDubbo注解可以理解为引入dubbo功能,其实在这里它起到的作用就是两个,
1、扫描类上面的@DubboService注解
2、扫描类中属性或者方法上面的@DubboReference注解
那为什么@EnableDubbo会被spring扫描到呢?
要回答这个问题,首先我们得看看@EnableDubbo的结构。可以看到,在@DubboComponentScan注解中有一个@Import注解,实际上spring能扫描到的就是这个@Import注解,通过扫描到@Import注解从而把import进来的
类变成BeanDefinition交给spring实例化。
具体spring如何扫描的,请看下面步骤:
1、通过spring上下文对象的实例化把
ConfigurationClassPostProcessor变成BeanDefinition2、ConfigurationClassPostProcessor对@Import的扫描
由于ConfigurationClassPostProcessor类是一个BeanDefinitionRegistryPostProcessor类型的,所以在spring容器中它会优先被实例化,实例化的地方在refresh核心方法的:所以当ConfigurationClassPostProcessor实例化的时候就调用到postProcessBeanDefinitionRegistry方法,方法逻辑如下:
就是在上面方面里面的this.reader.loadBeanDefinitions(configClasses);这行代码对所有BeanDefinition中对应类上如果有@Import注解进行了解析处理,这样spring就能够扫描的@EnableDubbo注解了。
2.3.2 DubboComponentScanRegistrar
DubboComponentScanRegistrar类是通过@EnableDubbo上面的@DubboComponentScan注解import进来的,它是一个ImportBeanDefinitionRegistrar类型的,所有当被引入进来以后就会被spring调用到它的registerBeanDefinitions方法,代码如下:
至于为什么spring能调到这个方法,起调用逻辑还是在this.reader.loadBeanDefinitions(configClasses);这行代码里面,具体调用代码:
我们在来看看registerBeanDefinitions方法做了些什么, registerCommonBeans(registry);方法前面我们分析过,注册了两个比较重要的类
1、ReferenceAnnotationBeanPostProcessor
2、DubboBootstrapApplicationListener
registerServiceAnnotationPostProcessor(packagesToScan, registry);这行代码里面又注册了一个比较重要的类,ServiceAnnotationPostProcessor
所以该方法其实核心就是注册了三个比较重要的类给了spring容器:
1、ReferenceAnnotationBeanPostProcessor
2、DubboBootstrapApplicationListener
3、ServiceAnnotationPostProcessor
DubboBootstrapApplicationListener这个类前面我们分析过,它就是在spring容器启动完成后通过spring发布一个spring容器启动完成的事件,然后该类捕获到事件,通过捕获事件来完成服务的发布和引用的,这里就不再赘述了。现在主要分析ServiceAnnotationPostProcessor和ReferenceAnnotationBeanPostProcessor
2.3.3 ServiceAnnotationPostProcessor
首先这个ServiceAnnotationPostProcessor类是干什么的呢?
这个类的作用就是用来扫描类上面的@DubboService注解的,就只有这个功能。
该类的类型是BeanDefinitionRegistryPostProcessor类型的。所以它会被spring调用到postProcessBeanDefinitionRegistry方法,调用逻辑如下:
OK,从上面的分析,我们知道,扫描到有@DubboService注解的类以后,实际上会创建跟该类对应的ServiceBean的实例,也就是有一个@DubboService注解的类就会对应一个ServiceBean的实例在spring容器中。那么又回到了上面xml分析的流程了,ServiceBean实例化走到afterPropertiesSet方法,然后spring容器启动完成走到dubbo的监听器完成服务发布了。
2.3.4 ReferenceAnnotationBeanPostProcessor
ReferenceAnnotationBeanPostProcessor的作用就是完成@DubboReference属性或者方法的依赖注入,其依赖注入的流程也是完全依赖spring的,所以我们必须要掌握spring的依赖注入流程,其实spring的依赖注入核心就两点;
2.3.4.1 spring的依赖注入
1、注解的收集
2、实例的注入
以@Autowired注解的属性来分析spring的依赖注入,例如:
1、@Autowired注解收集
注解收集的核心流程
对应的接口类型MergedBeanDefinitionPostProcessor,这个类型的BeanPostProcessor的埋点就是用来处理注解收集这个功能点的,只有关系该功能点的类才会对该接口的方法进行实现,其他不关心的可以不管MergedBeanDefinitionPostProcessor该接口的方法实现,也就是方法可以直接是一个空方法。
AutowiredAnnotationBeanPostProceessor类就是用来对@Autowired注解进行支持的。该类的注册是在spring上下文对象的构造函数的完成注册的。
注解的收集就完成了
2、@Autowired的依赖注入
依赖注入的核心方法:
这里又会调用到AutowiredAnnotationBeanPostProceessor类的方法进行依赖注入。
通过前面的收集结果,我们知道了哪些属性获取方法有注解,那么在这里我们只要根据有注解的属性进行依赖注入就可以了,这里就不再赘述了。
2.3.4.2 dubbo的依赖注入
其实dubbo的依赖注入流程跟spring是一模一样的,也是借助BeanPostProcessor类型的接口来实现,只是这个类是ReferenceAnnotationBeanPostProcessor
OK,我们来一个示例:
也是两个步骤,只是这两个步骤是由ReferenceAnnotationBeanPostProcessor它来完成的。
1、@DubboReference注解收集
2、实例的依赖注入
1、@DubboReference注解收集
收集的逻辑跟spring是一模一样的,如图:会走到ReferenceAnnotationBeanPostProcessor类中进行注解收集;
prepareInjection(metadata);的核心代码贴一下:
总结一下,收集注解会收集@DubboReference注解的属性或方法,然后还会创建跟@DubboReference对应的ReferenceBean对象,因为要完成代理的生成和服务的引用。
2、实例的依赖注入
@DubboReference属性的依赖注入,流程跟spring也是一样的,处理类是ReferenceAnnotationBeanPostProcessor会走到ReferenceAnnotationBeanPostProcessor类中的postProcessPropertyValues方法完成属性依赖注入
前面创建了ReferenceBean对象,其中有一个ReferenceBean对象的id就是userService.所有这里getBean会获取到ReferenceBean的实例或者其FactoryBean的getObject返回的实例,其实ReferenceBean是有实现FactoryBean接口的,所有这里会返回getObject返回的实例,我们看看ReferenceBean。
所以从这个流程看,@DubboReference依赖注入的对象其实就一个spring的代理对象,然后用这个代理对象调用的时候,最终会调到TargetSource对象的getTarget方法,由这个方法会调到referenceConfig.get()方法生成dubbo的代理对象,referenceConfig.get()这个方法也是引用dubbo服务的核心方法。
