11. Dubbo与Spring整合 - 原理总结
1. 开篇
本文对Dubbo与Spring整合原理整个过程做一个总结。
二、Dubbo与Spring整合原理——@DubboService解析
三、Dubbo与Spring整合原理—@DubboReference
Dubbo与Spring整合在启动过程中,需要经历3个主要的步骤:
- 解析配置文件
- 解析@DubboService注解
- 解析@DubboReference注解
@Configuration
@EnableDubbo(scanBasePackages = "org.apache.dubbo.demo.provider")
@PropertySource("classpath:/spring/dubbo-provider.properties")
public class ProviderConfiguration {
@Bean
public RegistryConfig registryConfig() {
RegistryConfig registryConfig = new RegistryConfig();
registryConfig.setAddress("zookeeper://127.0.0.1:2181");
return registryConfig;
}
}
2. 解析配置文件
加载配置文件是由@PropertySource
注解将properties
的配置加载解析放入environment
对象中。
解析Dubbo相关的配置是由@EnableDubboConfig
负责的,@EnableDubboConfig
导入了一个类DubboConfigConfigurationRegistrar
,这个类将Dubbo的配置规则和配置类进行一一绑定。无论是单项配置还是多个配置,对应的配置类是一样的,对应关系如下:
单个解析示例:
dubbo.application.name=dubbo-demo-provider-application
此配置前缀为dubbo.application
,会生成一个ApplicationConfig
类型的BeanDefinition,其name的属性值为dubbo-demo-provider-application
。
多个解析示例:
dubbo.protocols.first.name=dubbo
dubbo.protocols.first.port=20880
dubbo.protocols.second.name=dubbo
dubbo.protocols.second.port=20881
此配置前缀为dubbo.protocols
,他会生成两个ProtocolConfig
类型的BeanDefinition
,他们的beanName
分别为first
、second
。
解析配置文件主要过程如下:
- 读取
properties或yml
配置文件,将配置解析为key-value形式,并放入environment对象中。 - 解析
DubboConfigConfiguration.Single
注解,处理注解上配置prefix与配置类的关系。 - 解析
DubboConfigConfiguration.Multiple
注解,处理注解上配置prefix与配置类的关系。 - 解析上述注解后,将获取到的注解进行遍历,根据
multiple
属性分类处理。 - 获取配置
prefix
对应的所有配置属性值(从environment
对象中获取)。 - 将
properties或yml
配置生成对应的Bean
。 - 注册
BeanPOSTProcessor
处理属性值。
下面是讲配置文件的解析过程用流程图表示:
3. 解析@DubboService
@DubboService
注解表示这个类属于一个Dubbo
服务,解析出服务进行服务导出,并提供服务。
解析@DubboService
的主要逻辑如下:
- 注册一个
ServiceClassPostProcessor
- 获取扫描路径,对扫描路径进行扫描
- 获取哪些类上标有
@DubboService
注解 - 解析含有
@DubboService
注解的类,生成对应的BeanDefinition
- 根据
@DubboService
配置进行赋值并进行注册
@DubboService
解析后会生成两个Bean
,一个是Spring
的普通Bean
,一个是属于Dubbo服务的ServiceBean
。
ServiceBean
表示一个Dubbo服务,它内部含有一些重要的参数,例如:
interface
,表示Dubbo
服务的接口。parameters
,服务参数包含DubboService
注解的信息。application
,表示这个服务所归属的应用。protocols
,表示服务所使用的协议,Dubbo服务可能有多个协议。registries
,表示服务所要注册的注册中心,注册中心也可能包含多个。ref
,表示服务的具体实现类,其属性值为Spring
容器的一个Bean
。
4. 解析@DubboReference
被@DubboReference
注解标注的属性,代表要引入一个服务,代表一个注入点。@DubboReference
注解是由ReferenceAnnotationBeanPostProcessor
类来处理的。
Spring在进行依赖注入时,是调用AbstractAnnotationBeanPostProcessor
类的postProcessPropertyValues
方法来为属性赋值。
在Spring进行赋值操作时,需要先获取一个对象,这个对象就是ReferenceAnnotationBeanPostProcessor
类的doGetInjectedBean
的方法来获取一个对象,这个对象是一个代理对象。
在生成这个代理对象时,需要判断:
- 要引入的这个Dubbo服务是否为本地服务,不是的话就按照Dubbo的逻辑生成一个代理对象。
- 要引入的这个Dubbo服务是否被引入过了,如果已经引入过了,就直接拿来用不需要重复生成了。
如何判断当前所引入的服务是本地的一个服务?
我们知道在生成ServiceBean
的时候,beanName
的生成规则为接口类型+group+version
。而在生成referencedBeanName
的时候,生成的规则和ServiceBean
的beanName
是一致的,所以进行对比一下,如果是一致的直接调用ReferenceBean.get就可以了。
如何判断当前所引入的这个服务是否已经被引入过了呢?
首先根据@DubboReference
注解的所有信息+属性接口类型生成一个字符串作为beanName
,去Spring容器查找是否有对应的缓存,如果没有的话,则把ReferenceBean
对象作为bean放到Spring容器中。
@DubboReference对象注入流程如下
5. 后记
关于Dubbo与Spring整合流程这里就基本介绍完了,后面会介绍Dubbo服务导出以及引入的具体过程。
作者:Java星辰 链接:https://juejin.cn/post/7174912138773790780