likes
comments
collection
share

Dubbo源码|十一、Dubbo与Spring整合原理总结

作者站长头像
站长
· 阅读数 14

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第15天,点击查看活动详情

开篇

本文对Dubbo与Spring整合原理整个过程做一个总结。

一、Dubbo与Spring整合原理—配置解析

二、Dubbo与Spring整合原理——@DubboService解析

三、Dubbo与Spring整合原理—@DubboReference

Dubbo与Spring整合在启动过程中,需要经历3个主要的步骤:

  1. 解析配置文件
  2. 解析@DubboService注解
  3. 解析@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; 
    } 
}

解析配置文件

加载配置文件是由@PropertySource注解将properties的配置加载解析放入environment对象中。

解析Dubbo相关的配置是由@EnableDubboConfig负责的,@EnableDubboConfig导入了一个类DubboConfigConfigurationRegistrar,这个类将Dubbo的配置规则和配置类进行一一绑定。无论是单项配置还是多个配置,对应的配置类是一样的,对应关系如下:

Dubbo源码|十一、Dubbo与Spring整合原理总结

单个解析示例:

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分别为firstsecond

解析配置文件主要过程如下:

  1. 读取properties或yml配置文件,将配置解析为key-value形式,并放入environment对象中。
  2. 解析DubboConfigConfiguration.Single注解,处理注解上配置prefix与配置类的关系。
  3. 解析DubboConfigConfiguration.Multiple注解,处理注解上配置prefix与配置类的关系。
  4. 解析上述注解后,将获取到的注解进行遍历,根据multiple属性分类处理。
  5. 获取配置prefix对应的所有配置属性值(从environment对象中获取)。
  6. properties或yml配置生成对应的Bean
  7. 注册BeanPOSTProcessor处理属性值。

下面是讲配置文件的解析过程用流程图表示:

Dubbo源码|十一、Dubbo与Spring整合原理总结

解析@DubboService

@DubboService注解表示这个类属于一个Dubbo服务,解析出服务进行服务导出,并提供服务。

解析@DubboService的主要逻辑如下:

  1. 注册一个ServiceClassPostProcessor
  2. 获取扫描路径,对扫描路径进行扫描
  3. 获取哪些类上标有@DubboService注解
  4. 解析含有@DubboService注解的类,生成对应的BeanDefinition
  5. 根据@DubboService配置进行赋值并进行注册

@DubboService解析后会生成两个Bean,一个是Spring的普通Bean,一个是属于Dubbo服务的ServiceBean

ServiceBean表示一个Dubbo服务,它内部含有一些重要的参数,例如:

  1. interface,表示Dubbo服务的接口。
  2. parameters,服务参数包含DubboService注解的信息。
  3. application,表示这个服务所归属的应用。
  4. protocols,表示服务所使用的协议,Dubbo服务可能有多个协议。
  5. registries,表示服务所要注册的注册中心,注册中心也可能包含多个。
  6. ref,表示服务的具体实现类,其属性值为Spring容器的一个Bean

Dubbo源码|十一、Dubbo与Spring整合原理总结

解析@DubboReference

@DubboReference注解标注的属性,代表要引入一个服务,代表一个注入点。@DubboReference注解是由ReferenceAnnotationBeanPostProcessor类来处理的。

Spring在进行依赖注入时,是调用AbstractAnnotationBeanPostProcessor类的postProcessPropertyValues方法来为属性赋值。

在Spring进行赋值操作时,需要先获取一个对象,这个对象就是ReferenceAnnotationBeanPostProcessor类的doGetInjectedBean的方法来获取一个对象,这个对象是一个代理对象。

在生成这个代理对象时,需要判断:

  1. 要引入的这个Dubbo服务是否为本地服务,不是的话就按照Dubbo的逻辑生成一个代理对象。
  2. 要引入的这个Dubbo服务是否被引入过了,如果已经引入过了,就直接拿来用不需要重复生成了。

如何判断当前所引入的服务是本地的一个服务?

我们知道在生成ServiceBean的时候,beanName的生成规则为接口类型+group+version。而在生成referencedBeanName的时候,生成的规则和ServiceBeanbeanName是一致的,所以进行对比一下,如果是一致的直接调用ReferenceBean.get就可以了。

如何判断当前所引入的这个服务是否已经被引入过了呢?

首先根据@DubboReference注解的所有信息+属性接口类型生成一个字符串作为beanName,去Spring容器查找是否有对应的缓存,如果没有的话,则把ReferenceBean对象作为bean放到Spring容器中。

@DubboReference对象注入流程如下

Dubbo源码|十一、Dubbo与Spring整合原理总结

后记

关于Dubbo与Spring整合流程这里就基本介绍完了,后面会介绍Dubbo服务导出以及引入的具体过程。