Dubbo源码|九、Dubbo与Spring整合原理—@DubboService
开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第12天,点击查看活动详情
Dubbo与Spring整合系列
二、Dubbo与Spring整合原理——@DubboService解析
三、Dubbo与Spring整合原理——@DubboReference解析
源码分析
本文主要介绍Dubbo里@DubboService注解的解析过程。
配置扫描路径
DubboComponentScan可以指定扫描路径,也可以指定扫描类。
例如:
// 指定扫描路径方式
@EnableDubbo(scanBasePackages = "org.apache.dubbo.demo.provider")
// 指定扫描类对应的包名方式
@EnableDubbo(scanBasePackageClasses = ProviderConfiguration.class)
Spring在解析DubboComponentScan注解时,会导入DubboComponentScanRegistrar这个类,这个类是解析Dubbo注解、路径的入口类。
@Import(DubboComponentScanRegistrar.class)
public @interface DubboComponentScan {
String[] value() default {};
String[] basePackages() default {};
Class<?>[] basePackageClasses() default {};
}
解析扫描路径以及Dubbo注解
DubboComponentScanRegistrar类实现了ImportBeanDefinitionRegistrar接口,在spring启动时,会调用registerBeanDefinitions方法。
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
Set<String> packagesToScan = getPackagesToScan(importingClassMetadata);
registerServiceClassPostProcessor(packagesToScan, registry);
registerCommonBeans(registry);
}
这个方法主要处理过程如下:
- 获取扫描路径
- 扫描解析并处理
@DubboService注解 - 处理
@DubboReference注解
获取扫描路径

该方法解析DubboComponentScan注解,获取注解属性值,即basePackages、basePackageClasses、value的值。其中,basePackages和value都是路径,而basePackageClasses是一个类的集合,Dubbo会截取类的package路径,最终返回的是解析路径的集合。
注册BeanPostProcessor
该方法主要作用为:
- 把
ServiceClassPostProcessor注册为一个Bean - 由于
ServiceClassPostProcessor实现了BeanDefinitionRegistryPostProcessor接口,所以在Spring启动时会调用postProcessBeanDefinitionRegistry方法 - 扫描哪些类上加了
@DubboService注解了,把这些类解析并生成BeanDefinition,生成两个类,一个为普通的Bean,一个为ServiceBean - 在生成的
ServiceBean中会监听ServiceBeanExportedEvent事件,在Spring容器启动完后,对Dubbo服务进行导出
private void registerServiceClassPostProcessor(Set<String> packagesToScan, BeanDefinitionRegistry registry) {
BeanDefinitionBuilder builder = rootBeanDefinition(ServiceClassPostProcessor.class);
builder.addConstructorArgValue(packagesToScan);
builder.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
AbstractBeanDefinition beanDefinition = builder.getBeanDefinition();
BeanDefinitionReaderUtils.registerWithGeneratedName(beanDefinition, registry);
}
此方法,将ServiceClassPostProcessor类生成为RootBeanDefinition,把扫描的路径作为ServiceClassPostProcessor类的构造方法参数,设置Bean的角色为ROLE_INFRASTRUCTURE与AOP有关,然后将生成的BeanDefinition进行注册。
ServiceClassPostProcessor实现类BeanDefinitionRegistryPostProcessor接口,在spring启动的时候,会调用postProcessBeanDefinitionRegistry方法。
处理BeanDefinition
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
registerInfrastructureBean(registry, DubboBootstrapApplicationListener.BEAN_NAME, DubboBootstrapApplicationListener.class);
Set<String> resolvedPackagesToScan = resolvePackagesToScan(packagesToScan);
if (!CollectionUtils.isEmpty(resolvedPackagesToScan)) {
registerServiceBeans(resolvedPackagesToScan, registry);
} else {
if (logger.isWarnEnabled()) {
logger.warn("packagesToScan is empty , ServiceBean registry will be ignored!");
}
}
}
此方法,现将DubboBootstrapApplicationListener注册成一个Bean,主要是用来监听spring的刷新和关闭事件。
调用resolvePackagesToScan方法对传进来的路径进行解析,替换占位符。
调用registerServiceBeans方法将对扫描到的类注册为ServiceBean。
注册ServiceBean

先定义一个扫描器,对传进来的扫描路径扫描哪些类上含有DubboService、org.apache.dubbo.config.annotation.Service、com.alibaba.dubbo.config.annotation.Service3个注解,如果类上有这些注解,就把这些类生成对应的BeanDefinition,然后再把BeanDefinition注册为Spring容器里的Bean。
拿到了BeanDefinition,接下来就该把BeanDefinition生成对应ServiceBean。通过调用registerServiceBean方法注册ServiceBean

该方法主要处理过程如下:
- 调用
resolveClass方法,将BeanDefinition中的beanClassName进行加载,生成类对象。 - 解析
@DubboService注解,获取注解里配置的属性值。 - 解析实现类对应的接口。
- 获取
BeanDefinition中的beanName,为ServiceBean的ref属性值做准备。 - 调用
buildServiceBeanDefinition构造出ServiceBeanDefinition。 - 将构造出的
ServiceBeanDefinition进行注册。
构建DubboService的BeanDefinition

该方法主要处理过程如下:
- 将
ServiceBean生成一个RootBeanDefinition - 拿到这个
BeanDefinition所有属性 - 通过
propertyValues.addPropertyValues,将@DubboService注解配置的信息赋值给ServiceBean对应的BeanDefinition。被忽略的属性ignoreAttributeNames除外,因为这些属性有些特殊,不是简单数据类型,需要进行特殊处理。propertyValues可以对一些简单的数据类型进行赋值,比如String、int等。 - 调用
addPropertyReference方法为ref属性进行赋值,传进去的参数数beanName,spring 根据beanName去找到对应的bean对象,赋值是beanName对应的具体对象。 - 为其他刚才忽略的属性进行赋值,
provider、application、module等。 - 像
registry、protocol可以为多个值的属性,进行转换为RuntimeBeanReference集合进行赋值。
后记
@DubboService解析以及处理基本上已经结束了,至于Dubbo是如何对外暴露提供服务的,这块后面再进行介绍。
转载自:https://juejin.cn/post/7173843865311379470