注解配置
本文基于 Dubbo 2.7.1-SNAPSHOT 版本,望知悉。
1. 概述
在 Dubbo 提供的几种方式中,注解配置慢慢变成大家最常用的方式。
如果胖友不熟悉,可以查看如下文档:
2. 使用示例
我们来看看 dubbo-demo-annotation 项目下的 dubbo-demo-annotation-provider 子项目提供的 Dubbo Provider 示例。代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
// Application.java
public class Application {
/**
* In order to make sure multicast registry works, need to specify '-Djava.net.preferIPv4Stack=true' before
* launch the application
*/
public static void main(String[] args) throws Exception {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(ProviderConfiguration.class);
context.start();
System.in.read();
}
@Configuration
@EnableDubbo(scanBasePackages = "org.apache.dubbo.demo.provider") // <1>
@PropertySource("classpath:/spring/dubbo-provider.properties") // <2>
static class ProviderConfiguration {
@Bean // <3>
public RegistryConfig registryConfig() {
RegistryConfig registryConfig = new RegistryConfig();
registryConfig.setAddress("multicast://224.5.6.7:1234");
return registryConfig;
}
}
}
- <1> 处,使用 @EnableDubbo 注解,配置扫描 “org.apache.dubbo.demo.provider” 目录下的 @Service 和 @Reference Bean 对象。
- <2> 处,使用 @PropertySource 注解,导入 “classpath:/spring/dubbo-provider.properties” 配置文件。
- <3> 处,通过 @Bean 注解方法,创建 RegistryConfig Bean 对象,即注册中心。
- 通过使用 Java Config + 注解的方式,相比 XML 来说,会更加熟悉一些~
下面,我们就来看看具体的源码落。本文涉及的类,主要如下图所示:
3. @EnableDubbo
org.apache.dubbo.config.spring.context.annotation.@EnableDubbo 注解,是 @EnableDubboConfig 和 @DubboComponentScan 的组合注解,使用时更加便利。代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
// EnableDubbo.java
/**
* Enables Dubbo components as Spring Beans, equals
*
{
@link DubboComponentScan} and
{
@link EnableDubboConfi;
}
}
combination.
* <p>
* Note :
{
@link EnableDubbo;
}
must base on Spring Framework 4.2 and above
*
* @see DubboComponentScan
* @see EnableDubboConfig
* @since 2.5.8
*/
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
@EnableDubboConfig // 开启 Dubbo Config
@DubboComponentScan // 扫描 Dubbo @Service 和 @Reference Bean
public @interface EnableDubbo {
/**
* 配置 @DubboComponentScan 注解,扫描的包
*
* Base packages to scan for annotated @Service classes. <p>
* Use
{
@link #scanBasePackageClasses();
}
for a type-safe alternative to String-based
* package names.
*
* @return the base packages to scan
* @see DubboComponentScan#basePackages()
*/
@AliasFor(annotation = DubboComponentScan.class, attribute = "basePackages")
String[] scanBasePackages() default {}
/**
* 配置 @DubboComponentScan 注解,扫描的类
*
* Type-safe alternative to
{
@link #scanBasePackages();
}
for specifying the packages to
* scan for annotated @Service classes. The package of each class specified will be scanned.
*
* @return classes from the base packages to scan
* @see DubboComponentScan#basePackageClasses
*/
@AliasFor(annotation = DubboComponentScan.class, attribute = "basePackageClasses")
Class<?>[] scanBasePackageClasses() default {}
/**
* 配置 @EnableDubboConfig 注解,配置是否绑定到多个 Spring Bean 上
*
* It indicates whether
{
@link AbstractConfig;
}
binding to multiple Spring Beans.
*
* @return the default value is <code>false</code>
* @see EnableDubboConfig#multiple()
*/
@AliasFor(annotation = EnableDubboConfig.class, attribute = "multiple")
boolean multipleConfig() default false;
}
- 注意看下具体的注释。
通过 @EnableDubbo 可以在指定的包名下(通过 scanBasePackages 属性),或者指定的类中(通过 scanBasePackageClasses 属性)扫描 Dubbo 的服务提供者(以 @Service 注解)以及 Dubbo 的服务消费者(以 @Reference 注解)。
扫描到 Dubbo 的服务提供方和消费者之后,对其做相应的组装并初始化,并最终完成服务暴露或者引用的工作。
4. @EnableDubboConfig
org.apache.dubbo.config.spring.context.annotation.@EnableDubboConfig 注解,开启 Dubbo 配置。代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
// EnableDubboConfig.java
/**
* As a convenient and multiple
{
@link EnableDubboConfigBinding;
}
* in default behavior , is equal to single bean bindings with below convention prefixes of properties:
* <ul>
* <li>
{
@link ApplicationConfig;
}
binding to property : "dubbo.application"</li>
* <li>
{
@link ModuleConfig;
}
binding to property : "dubbo.module"</li>
* <li>
{
@link RegistryConfig;
}
binding to property : "dubbo.registry"</li>
* <li>
{
@link ProtocolConfig;
}
binding to property : "dubbo.protocol"</li>
* <li>
{
@link MonitorConfig;
}
binding to property : "dubbo.monitor"</li>
* <li>
{
@link ProviderConfig;
}
binding to property : "dubbo.provider"</li>
* <li>
{
@link ConsumerConfig;
}
binding to property : "dubbo.consumer"</li>
* </ul>
* <p>
* In contrast, on multiple bean bindings that requires to set
{
@link #multiple();
}
to be <code>true</code> :
* <ul>
* <li>
{
@link ApplicationConfig;
}
binding to property : "dubbo.applications"</li>
* <li>
{
@link ModuleConfig;
}
binding to property : "dubbo.modules"</li>
* <li>
{
@link RegistryConfig;
}
binding to property : "dubbo.registries"</li>
* <li>
{
@link ProtocolConfig;
}
binding to property : "dubbo.protocols"</li>
* <li>
{
@link MonitorConfig;
}
binding to property : "dubbo.monitors"</li>
* <li>
{
@link ProviderConfig;
}
binding to property : "dubbo.providers"</li>
* <li>
{
@link ConsumerConfig;
}
binding to property : "dubbo.consumers"</li>
* </ul>
*
* @see EnableDubboConfigBinding
* @see DubboConfigConfiguration
* @see DubboConfigConfigurationSelector
* @since 2.5.8
*/
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
@Import(DubboConfigConfigurationRegistrar.class)
public @interface EnableDubboConfig {
/**
* It indicates whether binding to multiple Spring Beans.
*
* 配置是否绑定到多个 Spring Bean 上
*
* @return the default value is <code>false</code>
* @revised 2.5.9
*/
boolean multiple() default false;
}
- 关于 multiple 属性,可能第一眼会有点懵逼,那咋整呢?
- 第一步,可以看看 《Dubbo 新编程模型之外部化配置 —— @EnableDubboConfig》 对 @EnableDubboConfig 注解的介绍。
- 第二步,我们在接下来会看具体的源码,会更易懂一些。
- @Import(DubboConfigConfigurationRegistrar.class)「4.1 DubboConfigConfigurationRegistrar」 注解,表明使用 DubboConfigConfigurationRegistrar 类进行导入。详细的,我们继续来看 。
4.1 DubboConfigConfigurationRegistrar
org.apache.dubbo.config.spring.context.annotation.DubboConfigConfigurationRegistrar ,实现 ImportBeanDefinitionRegistrar 接口,处理 @EnableDubboConfig 注解,注册相应的 DubboConfigConfiguration 到 Spring 容器中。代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
// DubboConfigConfigurationRegistrar.java
/**
* Dubbo
{
@link AbstractConfig Config}
{
@link ImportBeanDefinitionRegistrar registe;
}
}
,
* which order can be configured
*
* @see EnableDubboConfig
* @see DubboConfigConfiguration
* @see Ordered
* @since 2.5.8
*/
public class DubboConfigConfigurationRegistrar implements ImportBeanDefinitionRegistrar {
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
// 获得 @EnableDubboConfig 注解的属性
AnnotationAttributes attributes = AnnotationAttributes.fromMap(
importingClassMetadata.getAnnotationAttributes(EnableDubboConfig.class.getName()));
// 获得 multiple 属性
boolean multiple = attributes.getBoolean("multiple");
// 如果为 true,则注册 DubboConfigConfiguration.Multiple Bean 对象
if (multiple) {
AnnotatedBeanDefinitionRegistryUtils.registerBeans(registry, DubboConfigConfiguration.Multiple.class);
}
// 如果为 false,则注册 DubboConfigConfiguration.Single Bean 对象
else {
AnnotatedBeanDefinitionRegistryUtils.registerBeans(registry, DubboConfigConfiguration.Single.class);
}
}
}
// AnnotatedBeanDefinitionRegistryUtils.java
public static void registerBeans(BeanDefinitionRegistry registry, Class<?>... annotatedClasses) {
if (ObjectUtils.isEmpty(annotatedClasses)) {
return;
}
boolean debugEnabled = logger.isDebugEnabled();
// 创建 AnnotatedBeanDefinitionReader 对象
AnnotatedBeanDefinitionReader reader = new AnnotatedBeanDefinitionReader(registry);
if (debugEnabled) {
logger.debug(registry.getClass().getSimpleName() + " will register annotated classes : "
+ Arrays.asList(annotatedClasses) + " .");
}
// 注册
reader.register(annotatedClasses);
}
- 根据 @EnableDubboConfig 注解上的 multiple 属性的不同,创建 DubboConfigConfiguration.Multiple 或 DubboConfigConfiguration.Single 对象,注册到 Spring 容器中。
4.2 DubboConfigConfiguration
org.apache.dubbo.config.spring.beans.factory.annotation.DubboConfigConfiguration ,Dubbo AbstractConfig 配置类。代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
// DubboConfigConfiguration.java
/**
* Dubbo
{
@link AbstractConfig Config}
{
@link Configuratio;
}
}
*
* @see Configuration
* @see EnableDubboConfigBindings
* @see EnableDubboConfigBinding
* @see ApplicationConfig
* @see ModuleConfig
* @see RegistryConfig
* @see ProtocolConfig
* @see MonitorConfig
* @see ProviderConfig
* @see ConsumerConfig
* @see org.apache.dubbo.config.ConfigCenterConfig
* @since 2.5.8
*/
public class DubboConfigConfiguration {
/**
* Single Dubbo
{
@link AbstractConfig Config;
}
Bean Binding
*/
@EnableDubboConfigBindings({
@EnableDubboConfigBinding(prefix = "dubbo.application", type = ApplicationConfig.class),
@EnableDubboConfigBinding(prefix = "dubbo.module", type = ModuleConfig.class),
@EnableDubboConfigBinding(prefix = "dubbo.registry", type = RegistryConfig.class),
@EnableDubboConfigBinding(prefix = "dubbo.protocol", type = ProtocolConfig.class),
@EnableDubboConfigBinding(prefix = "dubbo.monitor", type = MonitorConfig.class),
@EnableDubboConfigBinding(prefix = "dubbo.provider", type = ProviderConfig.class),
@EnableDubboConfigBinding(prefix = "dubbo.consumer", type = ConsumerConfig.class),
@EnableDubboConfigBinding(prefix = "dubbo.config-center", type = ConfigCenterBean.class),
@EnableDubboConfigBinding(prefix = "dubbo.metadata-report", type = MetadataReportConfig.class)
})
public static class Single {
}
/**
* Multiple Dubbo
{
@link AbstractConfig Config;
}
Bean Binding
*/
@EnableDubboConfigBindings({
@EnableDubboConfigBinding(prefix = "dubbo.applications", type = ApplicationConfig.class, multiple = true),
@EnableDubboConfigBinding(prefix = "dubbo.modules", type = ModuleConfig.class, multiple = true),
@EnableDubboConfigBinding(prefix = "dubbo.registries", type = RegistryConfig.class, multiple = true),
@EnableDubboConfigBinding(prefix = "dubbo.protocols", type = ProtocolConfig.class, multiple = true),
@EnableDubboConfigBinding(prefix = "dubbo.monitors", type = MonitorConfig.class, multiple = true),
@EnableDubboConfigBinding(prefix = "dubbo.providers", type = ProviderConfig.class, multiple = true),
@EnableDubboConfigBinding(prefix = "dubbo.consumers", type = ConsumerConfig.class, multiple = true),
@EnableDubboConfigBinding(prefix = "dubbo.config-centers", type = ConfigCenterBean.class, multiple = true),
@EnableDubboConfigBinding(prefix = "dubbo.metadata-reports", type = MetadataReportConfig.class, multiple = true)
})
public static class Multiple {
}
}
- 乍眼一看,就是 Single 和 Multiple 内部类。其上都有 @@EnableDubboConfigBindings 和 @EnableDubboConfigBinding 注解。
- 前者 Single ,其上的注解, prefix 都是单数。
- 后者 Multiple ,其上的注解, prefix 都是复数,且有 multiple = true 。
- 那么会有什么效果呢?我们继续往 「4.3 @@EnableDubboConfigBindings」「4.4 @@EnableDubboConfigBinding」 和 看。
4.3 @EnableDubboConfigBindings
org.apache.dubbo.config.spring.context.annotation.@EnableDubboConfigBindings 注解,是 @EnableDubboConfigBinding 注解的数组。代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
// EnableDubboConfigBindings.java
/**
* Multiple
{
@link EnableDubboConfigBinding}
{
@link Annotatio;
}
}
*
* @since 2.5.8
* @see EnableDubboConfigBinding
*/
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(DubboConfigBindingsRegistrar.class)
public @interface EnableDubboConfigBindings {
/**
* The value of {
@link EnableDubboConfigBindings;
}
*
* @return non-null
*/
EnableDubboConfigBinding[] value();
}
- @Import(DubboConfigBindingsRegistrar.class)「4.3.1 DubboConfigBindingsRegistrar」 注解,表明使用 DubboConfigBindingsRegistrar 类进行导入。详细的,我们继续来看 。
4.3.1 DubboConfigBindingsRegistrar
org.apache.dubbo.config.spring.context.annotation.DubboConfigBindingsRegistrar ,实现 ImportBeanDefinitionRegistrar、EnvironmentAware 接口,处理 @EnableDubboConfigBindings 注解,注册相应的 Dubbo AbstractConfig 到 Spring 容器中。代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
// DubboConfigBindingsRegistrar.java
/**
*
{
@link AbstractConfig Dubbo Config} binding Bean registrar for
{
@link EnableDubboConfigBinding;
}
}
*
* @see EnableDubboConfigBindings
* @see DubboConfigBindingRegistrar
* @since 2.5.8
*/
public class DubboConfigBindingsRegistrar implements ImportBeanDefinitionRegistrar, EnvironmentAware {
private ConfigurableEnvironment environment;
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
// <1.1> 获得 @EnableDubboConfigBindings 注解
AnnotationAttributes attributes = AnnotationAttributes.fromMap(
importingClassMetadata.getAnnotationAttributes(EnableDubboConfigBindings.class.getName()));
// <1.2> 获得内部的 @EnableDubboConfigBinding 注解的数组
AnnotationAttributes[] annotationAttributes = attributes.getAnnotationArray("value");
// <2> 创建 DubboConfigBindingRegistrar 对象,并设置 environment 属性
DubboConfigBindingRegistrar registrar = new DubboConfigBindingRegistrar();
registrar.setEnvironment(environment);
// <3> 遍历 annotationAttributes 数组,使用 registrar 进行逐个 @EnableDubboConfigBinding 注解的注册对应的 Bean
for (AnnotationAttributes element : annotationAttributes) {
registrar.registerBeanDefinitions(element, registry);
}
}
@Override
public void setEnvironment(Environment environment) {
Assert.isInstanceOf(ConfigurableEnvironment.class, environment);
this.environment = (ConfigurableEnvironment) environment;
}
}
- <1.1> 、 <1.2> 处,获得 @EnableDubboConfigBindings 注解,从而后面获得内部的 @EnableDubboConfigBinding 注解的数组。
- <2> 处,创建 DubboConfigBindingRegistrar 对象,并设置 environment 属性。
- <3> 处,遍历 annotationAttributes 数组,使用 registrar ,调用 DubboConfigBindingRegistrar#registerBeanDefinitions(AnnotationAttributes attributes, BeanDefinitionRegistry registry) 方法,进行逐个 @EnableDubboConfigBinding 注解的注册对应的 Bean 。
- 在下文中,我们会看到 DubboConfigBindingRegistrar 本来就是用来处理 EnableDubboConfigBinding 注解。
4.4 @EnableDubboConfigBinding
org.apache.dubbo.config.spring.context.annotation.@EnableDubboConfigBinding 注解,代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
// EnableDubboConfigBinding.java
@Target(
{
ElementType.TYPE, ElementType.ANNOTATION_TYPE;
}
)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Repeatable(EnableDubboConfigBindings.class)
@Import(DubboConfigBindingRegistrar.class)
public @interface EnableDubboConfigBinding {
/**
* The name prefix of the properties that are valid to bind to
{
@link AbstractConfig Dubbo Config;
}
.
*
* 配置前缀
*
* @return the name prefix of the properties to bind
*/
String prefix();
/**
* 配置类
*
* The binding type of
{
@link AbstractConfig Dubbo Config;
}
.
*
* @see AbstractConfig
* @see ApplicationConfig
* @see ModuleConfig
* @see RegistryConfig
*/
Class<? extends AbstractConfig> type();
/**
* 是否 multiple
*
* It indicates whether
{
@link #prefix();
}
binding to multiple Spring Beans.
*
* @return the default value is <code>false</code>
*/
boolean multiple() default false;
}
- 每个属性,看其上的代码注释。
- @Import(DubboConfigBindingRegistrar.class)「4.4.1 DubboConfigBindingRegistrar」 注解,表明使用 DubboConfigBindingRegistrar 类进行导入。详细的,我们继续来看 。
4.4.1 DubboConfigBindingRegistrar
org.apache.dubbo.config.spring.context.annotation.DubboConfigBindingRegistrar ,实现 ImportBeanDefinitionRegistrar、EnvironmentAware 接口,处理 @EnableDubboConfigBinding 注解,注册相应的 Dubbo AbstractConfig 到 Spring 容器中。
4.4.1.1 registerBeanDefinitions
实现 #registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) 方法,处理 @EnableDubboConfigBinding 注解,注册相应的 Dubbo AbstractConfig 到 Spring 容器中。代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
//
DubboConfigBindingRegistrar.java
@Overridepublic
void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
// <1> 获得 @EnableDubboConfigBinding 注解
AnnotationAttributes attributes = AnnotationAttributes.fromMap(importingClassMetadata.getAnnotationAttributes(EnableDubboConfigBinding.class.getName()));
// <2> 注册配置对应的
Bean Definition 对象 registerBeanDefinitions(attributes, registry);
}
protected void registerBeanDefinitions(AnnotationAttributes attributes, BeanDefinitionRegistry registry) {
// <2.1> 获得 prefix 属性
String prefix = environment.resolvePlaceholders(attributes.getString("prefix"));
// 因为,有可能有占位符,所以要解析。 // <2.2> 获得 type 属性,即
AbstractConfig 的实现类 Class<? extends AbstractConfig> configClass = attributes.getClass("type");
// <2.3> 获得 multiple 属性 boolean multiple = attributes.getBoolean("multiple"); // <2.4> 注册
Dubbo Config Bean 对象 registerDubboConfigBeans(prefix, configClass, multiple, registry);
}
- <1> 处,获得 @EnableDubboConfigBinding 注解。
- <2> 注册配置对应的 Bean Definition 对象。 这里有个知识点要补充下,Spring 在创建 Bean 之前,会将 XML 配置或者注解配置,先解析成对应的 BeanDefinition 对象,然后在创建 Bean 对象。
- <2.1> 处,获得 prefix 属性。
- <2.2> 处,获得 type 属性,即 AbstractConfig 的实现类。
- <2.3> 处,获得 multiple 属性。
- <2.4> 处,调用 #registerDubboConfigBeans(String prefix, Class<? extends AbstractConfig> configClass, boolean multiple, BeanDefinitionRegistry registry) 方法,注册 Dubbo Config Bean 对象。
4.4.1.2 registerDubboConfigBeans
#registerDubboConfigBeans(String prefix, Class<? extends AbstractConfig> configClass, boolean multiple, BeanDefinitionRegistry registry) 方法,注册 Dubbo Config Bean 对象。代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
//
DubboConfigBindingRegistrar.javaprivate void registerDubboConfigBeans(String prefix, Class<? extends AbstractConfig> configClass, boolean multiple, BeanDefinitionRegistry registry) {
// <1.1> 获得 prefix 开头的配置属性
Map<String, Object> properties = PropertySourcesUtils.getSubProperties(environment.getPropertySources(), prefix);
// <1.2> 如果配置属性为空,则无需创建 if (CollectionUtils.isEmpty(properties))
{
if (log.isDebugEnabled())
{
log.debug("There is no property for binding to dubbo config class [" + configClass.getName() + "] within prefix [" + prefix + "]";
}
} return;
}
// <2> 获得配置属性对应的
Bean 名字的集合 Set<String> beanNames = multiple ? resolveMultipleBeanNames(properties) : Collections.singleton(resolveSingleBeanName(properties, configClass, registry));
// <3> 遍历 beanNames 数组,逐个注册 for (String beanName : beanNames) { // <3.1> 注注册;
Dubbo Config Bean 对象 registerDubboConfigBean(beanName, configClass, registry);
// <3.2> 注注册
Dubbo Config 对象对应的 DubboConfigBindingBeanPostProcessor 对象 registerDubboConfigBindingBeanPostProcessor(prefix, beanName, multiple, registry);
}
}
- <1.1> 处,调用 PropertySourcesUtils#getSubProperties(Iterable<PropertySource<?» propertySources, String prefix) 方法,获得 prefix 开头的配置属性。因为,后续会用这个属性,设置到创建的 Bean 对象中。
- <1.2> 处,如果配置属性为空,则无需创建。
- <2> 处,根据 multiple 的值,调用不同的方法,获得配置属性对应的 Bean 名字的集合。代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
//
DubboConfigBindingRegistrar.java
// 例如:dubbo.application.$
{
beanName;
}
.name=dubbo-demo-annotation-providerprivate
Set<String> resolveMultipleBeanNames(Map<String, Object> properties) {
Set<String> beanNames = new LinkedHashSet<String>();
for (String propertyName : properties.keySet()) {
// 获取上述示例的 $
{
beanName;
}
字符串 int index = propertyName.indexOf(".");
if (index > 0) {
String beanName = propertyName.substring(0, index);
beanNames.add(beanName);
}
}
return beanNames;
}
// 例如:dubbo.application.name=dubbo-demo-annotation-providerprivate
String resolveSingleBeanName(Map<String, Object> properties, Class<? extends AbstractConfig> configClass, BeanDefinitionRegistry registry) {
// 获得
Bean 的名字 String beanName = (String) properties.get("id");
// 如果定义,基于
Spring 提供的机制,生成对应的 Bean 的名字。例如说:org.apache.dubbo.config.ApplicationConfig#0 if (!StringUtils.hasText(beanName)) {
BeanDefinitionBuilder builder = BeanDefinitionBuilder.rootBeanDefinition(configClass);
beanName = BeanDefinitionReaderUtils.generateBeanName(builder.getRawBeanDefinition(), registry);
}
return beanName;
}
- 这两个方法,看看我提供的示例。
#resolveMultipleBeanNames(Map<String, Object> properties)方法,可能比较难理解一点。胖友可以增加如下到配置文件中:
1
2
3
# application.properties
dubbo.applications.x.name=biu
dubbo.applications.y.name=biubiubiu
此时,你需要指定
@ServiceBean 使用哪个应用。<3> 处,遍历 beanNames 数组,逐个注册。
- <3.1> 处,调用 #registerDubboConfigBean(String beanName, Class<? extends AbstractConfig> configClass, BeanDefinitionRegistry registry) 方法,注册 Dubbo Config Bean 对象。代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
//
DubboConfigBindingRegistrar.javaprivate void registerDubboConfigBean(String beanName, Class<? extends AbstractConfig> configClass, BeanDefinitionRegistry registry) {
// 创建
BeanDefinitionBuilder 对象 BeanDefinitionBuilder builder = BeanDefinitionBuilder.rootBeanDefinition(configClass);
// 获得
AbstractBeanDefinition 对象 AbstractBeanDefinition beanDefinition = builder.getBeanDefinition();
// 注册到 registry 中 registry.registerBeanDefinition(beanName, beanDefinition); if (log.isInfoEnabled())
{
log.info("The dubbo config bean definition [name : " + beanName + ", class : " + configClass.getName() + "] has been registered.");
}
}
此时,仅仅是通过酱紫的方式,创建了一个 Dubbo Config Bean 对象,并没有将配置属性,设置到该对象中。答案在 <3.2> 中。
- <3.2> 处,调用
#registerDubboConfigBindingBeanPostProcessor(String prefix, String beanName, boolean multiple, BeanDefinitionRegistry registry)方法,注册 Dubbo Config 对象对象的 DubboConfigBindingBeanPostProcessor 对象。代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
//
DubboConfigBindingRegistrar.javaprivate void registerDubboConfigBindingBeanPostProcessor(String prefix, String beanName, boolean multiple, BeanDefinitionRegistry registry) {
// 创建
BeanDefinitionBuilder 对象 Class<?> processorClass = DubboConfigBindingBeanPostProcessor.class;
BeanDefinitionBuilder builder = rootBeanDefinition(processorClass);
// 添加构造方法的参数为 actualPrefix 和 beanName 。即,创建
DubboConfigBindingBeanPostProcessor 对象,需要这两个构造参数 String actualPrefix = multiple ? PropertySourcesUtils.normalizePrefix(prefix) + beanName : prefix;
builder.addConstructorArgValue(actualPrefix).addConstructorArgValue(beanName);
// 获得
AbstractBeanDefinition 对象 AbstractBeanDefinition beanDefinition = builder.getBeanDefinition();
// 设置 role 属性 beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE); // 注册到 registry 中
BeanDefinitionReaderUtils.registerWithGeneratedName(beanDefinition, registry);
if (log.isInfoEnabled()) {
log.info("The BeanPostProcessor bean definition [" + processorClass.getName() + "] for dubbo config bean [name : " + beanName + "] has been registered.");
}
}
因为此时 Dubbo Config Bean 对象还未创建,所以需要等后续它真的创建之后,使用 DubboConfigBindingBeanPostProcessor 类,实现对对象(Bean 对象)的配置输入的设置。
至此,我们发现,需要继续挖掘,让我们继续来看 「DubboConfigBindingBeanPostProcessor」 类。
4.5 DubboConfigBindingBeanPostProcessor
org.apache.dubbo.config.spring.beans.factory.annotation.DubboConfigBindingBeanPostProcessor ,实现 BeanPostProcessor、ApplicationContextAware、InitializingBean 接口,处理 Dubbo AbstractConfig Bean 的配置属性注入。
4.5.1 构造方法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
//
DubboConfigBindingBeanPostProcessor.java/** * The prefix of Configuration Properties * * 配置属性的前缀 */private final String prefix;
/** * Binding Bean Name * * Bean 的名字 */private final String beanName;
private DubboConfigBinder dubboConfigBinder;
private ApplicationContext applicationContext;
/** * 是否忽略位置的属性 */private boolean ignoreUnknownFields = true;
/** * 是否忽略类型不对的属性 */private boolean ignoreInvalidFields = true;
/** *
@param
prefix the prefix of Configuration Properties *
@param
beanName the binding Bean Name */public DubboConfigBindingBeanPostProcessor(String prefix, String beanName) {
Assert.notNull(prefix, "The prefix of Configuration Properties must not be null");
Assert.notNull(beanName, "The name of bean must not be null");
this.prefix = prefix;
this.beanName = beanName;
}
- 所以,我们在上文中会看到,创建 DubboConfigBindingBeanPostProcessor Bean 时,会有 builder.addConstructorArgValue(actualPrefix).addConstructorArgValue(beanName); 一段的代码。
4.5.2 afterPropertiesSet
#afterPropertiesSet() 方法,设置 dubboConfigBinder 属性。代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
//
DubboConfigBindingBeanPostProcessor.java
@Overridepublic
void afterPropertiesSet() throws Exception {
// 获得(创建)DubboConfigBinder 对象 if (dubboConfigBinder == null)
{
try
{
dubboConfigBinder = applicationContext.getBean(DubboConfigBinder.class;
}
}
catch (BeansException ignored) { if (log.isDebugEnabled()) { log.debug("DubboConfigBinder
Bean can't be found in ApplicationContext.");
}
//
Use Default implementation dubboConfigBinder = createDubboConfigBinder(applicationContext.getEnvironment());
}
}
// 设置 ignoreUnknownFields、ignoreInvalidFields 属性 dubboConfigBinder.setIgnoreUnknownFields(ignoreUnknownFields);
dubboConfigBinder.setIgnoreInvalidFields(ignoreInvalidFields);
}/** *
Create {
@link
DubboConfigBinder
}
instance. * *
@param
environment *
@return
{
@link
DefaultDubboConfigBinder
}
*/protected DubboConfigBinder createDubboConfigBinder(Environment environment) {
// 创建
DefaultDubboConfigBinder 对象 DefaultDubboConfigBinder defaultDubboConfigBinder = new DefaultDubboConfigBinder();
// 设置 environment 属性 defaultDubboConfigBinder.setEnvironment(environment);
return defaultDubboConfigBinder;
}
- 关于 DefaultDubboConfigBinder 类,我们在下面的小节先来瞅瞅。
4.5.2.1 DubboConfigBinder
org.apache.dubbo.config.spring.context.properties.DubboConfigBinder ,继承 EnvironmentAware 接口,Dubbo Config Binder 接口。代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
//
DubboConfigBinder.java/** * {
@link
AbstractConfig DubboConfig
}
Binder * *
@see
AbstractConfig *
@see
EnvironmentAware *
@since
2.5.11 */public interface DubboConfigBinder extends EnvironmentAware {
/** * Set whether to ignore unknown fields, that is, whether to ignore bind * parameters that do not have corresponding fields in the target object. * <p>Default is "true". Turn this off to enforce that all bind parameters * must have a matching field in the target object. * *
@see
#bind */ void setIgnoreUnknownFields(boolean ignoreUnknownFields);
/** * Set whether to ignore invalid fields, that is, whether to ignore bind * parameters that have corresponding fields in the target object which are * not accessible (for example because of null values in the nested path). * <p>Default is "false". * *
@see
#bind */ void setIgnoreInvalidFields(boolean ignoreInvalidFields);
/** * Bind the properties to Dubbo Config Object under specified prefix. * *
@param
prefix *
@param
dubboConfig */ <C extends AbstractConfig> void bind(String prefix, C dubboConfig);
}```
- 后续的实现,我们会看到基于 Spring DataBinder 来实现。不了解 DataBinder 的胖友,可以看看 [《Spring 验证、数据绑定和类型转换》](https://my.oschina.net/u/2453016/blog/1512184)
文章。
### 4.5.2.2 DubboConfigBinder
org.apache.dubbo.config.spring.context.properties.AbstractDubboConfigBinder ,实现 DubboConfigBinder 接口,DubboConfigBinder 的抽象基类。代码如下:
```java
//
AbstractDubboConfigBinder.javapublic abstract class AbstractDubboConfigBinder implements DubboConfigBinder {
/** * PropertySource 数组(迭代) */ private Iterable<PropertySource<?>> propertySources;
private boolean ignoreUnknownFields = true;
private boolean ignoreInvalidFields = false;
/** * Get multiple {
@link
PropertySource propertySources
}
* *
@return
multiple {
@link
PropertySource propertySources
}
*/ protected Iterable<PropertySource<?>> getPropertySources() {
return propertySources;
}
public boolean isIgnoreUnknownFields() {
return ignoreUnknownFields;
}
@Override
public void setIgnoreUnknownFields(boolean ignoreUnknownFields) {
this.ignoreUnknownFields = ignoreUnknownFields;
}
public boolean isIgnoreInvalidFields() {
return ignoreInvalidFields;
}
@Override
public void setIgnoreInvalidFields(boolean ignoreInvalidFields) {
this.ignoreInvalidFields = ignoreInvalidFields;
}
@Override
public final void setEnvironment(Environment environment) {
if (environment instanceof ConfigurableEnvironment) {
this.propertySources = ((ConfigurableEnvironment) environment).getPropertySources();
}
}
}
- 提供默认的属性。
4.5.2.3 DefaultDubboConfigBinder
org.apache.dubbo.config.spring.context.properties.DefaultDubboConfigBinder ,继承 AbstractDubboConfigBinder 抽象类,使用 Spring DataBinder ,将配置属性设置到 Dubbo Config 对象中。代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
//
DefaultDubboConfigBinder.java/** * Default {
@link
DubboConfigBinder
}
implementation based on Spring {
@link
DataBinder
}
*/public class DefaultDubboConfigBinder extends AbstractDubboConfigBinder {
@Override
public <C extends AbstractConfig> void bind(String prefix, C dubboConfig) {
// 将 dubboConfig 包装成
DataBinder 对象 DataBinder dataBinder = new DataBinder(dubboConfig);
//
Set ignored*
// 设置响应的 ignored* 属性 dataBinder.setIgnoreInvalidFields(isIgnoreInvalidFields());
dataBinder.setIgnoreUnknownFields(isIgnoreUnknownFields());
//
Get properties under specified prefix from PropertySources
// 获得 prefix 开头的配置属性
Map<String, Object> properties = PropertySourcesUtils.getSubProperties(getPropertySources(), prefix);
//
Convert Map to MutablePropertyValues
// 创建
MutablePropertyValues 对象 MutablePropertyValues propertyValues = new MutablePropertyValues(properties);
//
Bind
// 绑定配置属性到 dubboConfig 中 dataBinder.bind(propertyValues); }}
- 比较简单,胖友自己瞅一眼代码即可。
在 《Dubbo 源码分析 —— 集成 Spring Boot》 中,我们可以看到另外一个 AbstractDubboConfigBinder 的实现类 RelaxedDubboConfigBinder ,它是基于 Spring Boot Binder 进行实现。 因为艿艿没有深入了解过 Spring Boot Binder 相关,所以还说不出和 Spring DataBinder 的区别在哪。orz
4.5.3 postProcessBeforeInitialization
实现 #postProcessBeforeInitialization(Object bean, String beanName) 方法,设置配置属性到 Dubbo Config 中。代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
//
DubboConfigBindingBeanPostProcessor.java
@Overridepublic
Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
// 判断必须是 beanName ,并且是
AbstractConfig 类型 if (beanName.equals(this.beanName) && bean instanceof AbstractConfig) {
AbstractConfig dubboConfig = (AbstractConfig) bean;
// 设置属性到 dubboConfig 中 dubboConfigBinder.bind(prefix, dubboConfig); if (log.isInfoEnabled())
{
log.info("The properties of bean [name : " + beanName + "] have been binding by prefix of " + "configuration properties : " + prefix);
} } return bean;
}
至此,Dubbo Config 对象的创建和属性设置,已经完成。如果胖友还是有点懵逼,可以调试一次,没有什么复杂逻辑哟。
5. @DubboComponentScan
org.apache.dubbo.config.spring.context.annotation.@DubboComponentScan 注解,配置要扫描 @Service 和 @Reference 注解的包或者类们,从而创建对应的 Bean 对象。代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
//
DubboComponentScan.java/** * Dubbo Component Scan {
@link
Annotation
}
,scans the classpath for annotated components that will be auto-registered as * Spring beans. Dubbo-provided {
@link
Service
}
and {
@link
Reference
}
. * *
@see
Service *
@see
Reference *
@since
2.5.7 */
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(DubboComponentScanRegistrar.class)
public
@interface
DubboComponentScan {
/** * 和 {
@link
#basePackages()
}
等价 * * Alias for the {
@link
#basePackages()
}
attribute. Allows for more concise annotation * declarations e.g.: {
@code
@DubboComponentScan("org.my.pkg")
}
instead of * {
@code
@DubboComponentScan(basePackages="org.my.pkg")
}
. * *
@return
the base packages to scan */ String[] value() default {
}
;
/** * 要扫描的包的数组 * * Base packages to scan for annotated
@Service
classes. {
@link
#value()
}
is an * alias for (and mutually exclusive with) this attribute. * <p> * Use {
@link
#basePackageClasses()
}
for a type-safe alternative to String-based * package names. * *
@return
the base packages to scan */ String[] basePackages() default {
}
;
/** * 要扫描的类的数组 * * Type-safe alternative to {
@link
#basePackages()
}
for specifying the packages to * scan for annotated
@Service
classes. The package of each class specified will be * scanned. * *
@return
classes from the base packages to scan */ Class<?>[] basePackageClasses() default {
}
;
}
- @Import(DubboComponentScanRegistrar.class)「5.1 DubboComponentScanRegistrar」 注解,表明使用 DubboComponentScanRegistrar 类进行导入。详细的,我们继续来看 。
5.1 DubboComponentScanRegistrar
org.apache.dubbo.config.spring.context.annotation.DubboComponentScanRegistrar ,实现 ImportBeanDefinitionRegistrar 接口,处理 @DubboComponentScan 注解,注册相应的 ServiceAnnotationBeanPostProcessor 和 ReferenceAnnotationBeanPostProcessor 到 Spring 容器中。代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
//
DubboComponentScanRegistrar.java
@Overridepublic
void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
// <1> 获得要扫描的包
Set<String> packagesToScan = getPackagesToScan(importingClassMetadata);
// <2> 创建
ServiceAnnotationBeanPostProcessor Bean 对象,后续扫描 `
@Service
` 注解的类,创建对应的 Service Bean 对象 registerServiceAnnotationBeanPostProcessor(packagesToScan, registry);
// <3> 创建
ReferenceAnnotationBeanPostProcessor Bean 对象,后续扫描 `
@Reference
` 注解的类,创建对应的 Reference Bean 对象 registerReferenceAnnotationBeanPostProcessor(registry);
}
// ... 省略稍后调用的方法。
- <1> 处,调用 #getPackagesToScan(AnnotationMetadata metadata) 方法,获得要扫描的包。代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
//
DubboComponentScanRegistrar.javaprivate Set<String> getPackagesToScan(AnnotationMetadata metadata) {
// 获得 @DubboComponentScan 注解
AnnotationAttributes attributes = AnnotationAttributes.fromMap(metadata.getAnnotationAttributes(DubboComponentScan.class.getName()));
// 获得其上的属性
String[] basePackages = attributes.getStringArray("basePackages");
Class<?>[] basePackageClasses = attributes.getClassArray("basePackageClasses");
String[] value = attributes.getStringArray("value");
//
Appends value array attributes
// 情况一,将属性添加到 packagesToScan 集合中
Set<String> packagesToScan = new LinkedHashSet<String>(Arrays.asList(value));
packagesToScan.addAll(Arrays.asList(basePackages));
for (Class<?> basePackageClass : basePackageClasses) {
packagesToScan.add(ClassUtils.getPackageName(basePackageClass));
}
// 情况二,如果 packagesToScan 为空,则默认使用注解类所在的包 if (packagesToScan.isEmpty()) { return
Collections.singleton(ClassUtils.getPackageName(metadata.getClassName()));
}
return packagesToScan;
}
有两种情况,胖友看的时候,要注意下。
- <2> 处,调用 #registerServiceAnnotationBeanPostProcessor(Set packagesToScan, BeanDefinitionRegistry registry) 方法,创建 ServiceAnnotationBeanPostProcessor Bean 对象,后续扫描 @Service 注解的类,创建对应的 Service Bean 对象。代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
//
DubboComponentScanRegistrar.javaprivate void registerServiceAnnotationBeanPostProcessor(Set<String> packagesToScan, BeanDefinitionRegistry registry) {
// 创建
BeanDefinitionBuilder 对象 BeanDefinitionBuilder builder = BeanDefinitionBuilder.rootBeanDefinition(ServiceAnnotationBeanPostProcessor.class);
// 设置构造方法参数为 packagesToScan ,即
BeanDefinitionBuilder 扫描该包 builder.addConstructorArgValue(packagesToScan);
// 设置 role 属性 builder.setRole(BeanDefinition.ROLE_INFRASTRUCTURE); // 获得
AbstractBeanDefinition 对象 AbstractBeanDefinition beanDefinition = builder.getBeanDefinition();
// 注册到 registry 中
BeanDefinitionReaderUtils.registerWithGeneratedName(beanDefinition, registry);
}
关于 ServiceAnnotationBeanPostProcessor 类,我们在 「5.2 ServiceAnnotationBeanPostProcessor」 中,详细解析。
- <3> 处,调用 #registerReferenceAnnotationBeanPostProcessor(BeanDefinitionRegistry registry) 方法,创建 ReferenceAnnotationBeanPostProcessor Bean 对象,后续扫描 @Reference 注解的类,创建对应的 Reference Bean 对象。代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
//
DubboComponentScanRegistrar.javaprivate void registerReferenceAnnotationBeanPostProcessor(BeanDefinitionRegistry registry) {
//
Register
@Reference
Annotation Bean Processor BeanRegistrar.registerInfrastructureBean(registry, ReferenceAnnotationBeanPostProcessor.BEAN_NAME, ReferenceAnnotationBeanPostProcessor.class);
}
//
BeanRegistrar.javapublic static void registerInfrastructureBean(BeanDefinitionRegistry beanDefinitionRegistry, String beanName, Class<?> beanType) {
// 不存在 beanName 对应的
BeanDefinition 对象 if (!beanDefinitionRegistry.containsBeanDefinition(beanName)) {
// 创建
RootBeanDefinition 对象 RootBeanDefinition beanDefinition = new RootBeanDefinition(beanType);
// 设置 role beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
// 注册到 beanDefinitionRegistry 中 beanDefinitionRegistry.registerBeanDefinition(beanName, beanDefinition);
}}
关于 ReferenceAnnotationBeanPostProcessor 类,我们在 「5.3 ReferenceAnnotationBeanPostProcessor」 中,详细解析。
5.2 ServiceAnnotationBeanPostProcessor
org.apache.dubbo.config.spring.beans.factory.annotation.ServiceAnnotationBeanPostProcessor ,实现 BeanDefinitionRegistryPostProcessor、EnvironmentAware、ResourceLoaderAware、BeanClassLoaderAware 接口,扫描 @Service 注解的类,创建对应的 Spring BeanDefinition 对象,从而创建 Dubbo Service Bean 对象。
5.2.1 构造方法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
//
ServiceAnnotationBeanPostProcessor.java/** * 要扫描的包的集合 */private final Set<String> packagesToScan;
private Environment environment;
private ResourceLoader resourceLoader;
private ClassLoader classLoader;
public ServiceAnnotationBeanPostProcessor(String... packagesToScan) {
// 上述文章使用到的构造方法 this(Arrays.asList(packagesToScan));}public
ServiceAnnotationBeanPostProcessor(Collection<String> packagesToScan) {
this(new LinkedHashSet<String>(packagesToScan));
}
public ServiceAnnotationBeanPostProcessor(Set<String> packagesToScan) {
this.packagesToScan = packagesToScan;
}
5.2.2 postProcessBeanDefinitionRegistry
实现 #postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) 方法,扫描 @Service 注解的类,创建对应的 Spring BeanDefinition 对象,从而创建 Dubbo Service Bean 对象。代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
//
ServiceAnnotationBeanPostProcessor.java
@Overridepublic
void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
// <1> 解析 packagesToScan 集合。因为,可能存在占位符
Set<String> resolvedPackagesToScan = resolvePackagesToScan(packagesToScan);
// <2> 扫描 packagesToScan 包,创建对应的
Spring BeanDefinition 对象,从而创建 Dubbo Service Bean 对象。 if (!CollectionUtils.isEmpty(resolvedPackagesToScan)) {
registerServiceBeans(resolvedPackagesToScan, registry);
}
else {
if (logger.isWarnEnabled()) {
logger.warn("packagesToScan is empty , ServiceBean registry will be ignored!");
}
}
}
- <1> 处,调用 #resolvePackagesToScan(Set packagesToScan) 方法,解析 packagesToScan 集合。因为,可能存在占位符。代码如下:
1
2
3
4
5
6
7
8
9
10
//
ServiceAnnotationBeanPostProcessor.javaprivate Set<String> resolvePackagesToScan(Set<String> packagesToScan) {
Set<String> resolvedPackagesToScan = new LinkedHashSet<String>(packagesToScan.size());
// 遍历 packagesToScan 数组 for (String packageToScan : packagesToScan) { if (StringUtils.hasText(packageToScan)) { // 解析可能存在的占位符;
String resolvedPackageToScan = environment.resolvePlaceholders(packageToScan.trim());
// 添加到 resolvedPackagesToScan 中 resolvedPackagesToScan.add(resolvedPackageToScan);
} } return resolvedPackagesToScan;
}
- <2>「5.2.3 resolvePackagesToScan」 处,调用 #registerServiceBeans(Set packagesToScan, BeanDefinitionRegistry registry) 方法,扫描 packagesToScan 包,创建对应的 Spring BeanDefinition 对象,从而创建 Dubbo Service Bean 对象。详细解析,见 中。
5.2.3 resolvePackagesToScan
#registerServiceBeans(Set packagesToScan, BeanDefinitionRegistry registry) 方法,扫描 packagesToScan 包,创建对应的 Spring BeanDefinition 对象,从而创建 Dubbo Service Bean 对象。代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
//
ServiceAnnotationBeanPostProcessor.javaprivate void registerServiceBeans(Set<String> packagesToScan, BeanDefinitionRegistry registry) {
// <1.1> 创建
DubboClassPathBeanDefinitionScanner 对象 DubboClassPathBeanDefinitionScanner scanner = new DubboClassPathBeanDefinitionScanner(registry, environment, resourceLoader);
// <1.2> 获得
BeanNameGenerator 对象,并设置 beanNameGenerator 到 scanner 中 BeanNameGenerator beanNameGenerator = resolveBeanNameGenerator(registry);
scanner.setBeanNameGenerator(beanNameGenerator);
// <1.3> 设置过滤获得带有 @Service 注解的类 scanner.addIncludeFilter(new
AnnotationTypeFilter(Service.class));
// <2> 遍历 packagesToScan 数组 for (String packageToScan : packagesToScan) { //;
Registers
@Service
Bean first
// <2.1> 执行扫描 scanner.scan(packageToScan); //
Finds all BeanDefinitionHolders of
@Service
whether
@ComponentScan
scans or not.
// <2.2> 创建每个在 packageToScan 扫描到的类,对应的
BeanDefinitionHolder 对象,返回 BeanDefinitionHolder 集合 Set<BeanDefinitionHolder> beanDefinitionHolders = findServiceBeanDefinitionHolders(scanner, packageToScan, registry, beanNameGenerator);
// <2.3> 注册到 registry 中 if (!CollectionUtils.isEmpty(beanDefinitionHolders))
{
for (BeanDefinitionHolder beanDefinitionHolder : beanDefinitionHolders)
{
registerServiceBean(beanDefinitionHolder, registry, scanner;
}
}
if (logger.isInfoEnabled()) { logger.info(beanDefinitionHolders.size() + " annotated
Dubbo's
@Service
Components {
" + beanDefinitionHolders + "
}
were scanned under package[" + packageToScan + "]");
}
}
else {
if (logger.isWarnEnabled()) {
logger.warn("No Spring Bean annotating Dubbo's
@Service
was found under package[" + packageToScan + "]");
}
}
}
}
- <1.1>链接 处,创建 DubboClassPathBeanDefinitionScanner 对象。它是用于扫描指定包下符合条件的类,用于将每个符合条件的类,创建对应的 BeanDefinition 对象,从而创建 Bean 。关于 DubboClassPathBeanDefinitionScanner 类,胖友点击 瞅一眼即可。
- <1.2> 处,调用 #resolveBeanNameGenerator(BeanDefinitionRegistry registry) 方法,获得 BeanNameGenerator 对象,并设置 beanNameGenerator 到 scanner 中。代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
//
ServiceAnnotationBeanPostProcessor.java/** * It'd better to use BeanNameGenerator instance that should reference * {
@link
ConfigurationClassPostProcessor#componentScanBeanNameGenerator
}
, * thus it maybe a potential problem on bean name generation. * *
@param
registry {
@link
BeanDefinitionRegistry
}
*
@return
{
@link
BeanNameGenerator
}
instance *
@see
SingletonBeanRegistry *
@see
AnnotationConfigUtils#CONFIGURATION_BEAN_NAME_GENERATOR *
@see
ConfigurationClassPostProcessor#processConfigBeanDefinitions *
@since
2.5.8 */
@SuppressWarnings("Duplicates")
private BeanNameGenerator resolveBeanNameGenerator(BeanDefinitionRegistry registry) {
BeanNameGenerator beanNameGenerator = null;
// 如果是
SingletonBeanRegistry 类型,从中获得对应的 BeanNameGenerator Bean 对象 if (registry instanceof SingletonBeanRegistry) {
SingletonBeanRegistry singletonBeanRegistry = SingletonBeanRegistry.class.cast(registry);
beanNameGenerator = (BeanNameGenerator) singletonBeanRegistry.getSingleton(AnnotationConfigUtils.CONFIGURATION_BEAN_NAME_GENERATOR);
}
// 如果不存在,则创建
AnnotationBeanNameGenerator 对象 if (beanNameGenerator == null) {
if (logger.isInfoEnabled()) {
logger.info("BeanNameGenerator bean can't be found in BeanFactory with name [" + CONFIGURATION_BEAN_NAME_GENERATOR + "]");
logger.info("BeanNameGenerator will be a instance of " + AnnotationBeanNameGenerator.class.getName() + " , it maybe a potential problem on bean name generation.");
}
beanNameGenerator = new AnnotationBeanNameGenerator();
}
return beanNameGenerator;
}
- <1.3> 处,设置过滤获得带有 @Service 注解的类。关于 @Service 注解的具体的属性,本文就不过分介绍,胖友自己瞅瞅。
- <2> 处,遍历 packagesToScan 数组。
- <2.1> 处,调用 DubboClassPathBeanDefinitionScanner#scan(String… basePackages) 方法,执行扫描。
- <2.2>「5.2.4 findServiceBeanDefinitionHolders」 处,调用 #findServiceBeanDefinitionHolders(ClassPathBeanDefinitionScanner scanner, String packageToScan, BeanDefinitionRegistry registry, BeanNameGenerator beanNameGenerator) 方法,创建每个在 packageToScan 扫描到的类,对应的 BeanDefinitionHolder 对象,返回 BeanDefinitionHolder 集合。详细解析 ,见 中。
- <2.3>「5.2.5 registerServiceBean」 处,调用 #registerServiceBean(BeanDefinitionHolder beanDefinitionHolder, BeanDefinitionRegistry registry, DubboClassPathBeanDefinitionScanner scanner) 方法,注册到 registry 中。详细解析,见 中。
5.2.4 findServiceBeanDefinitionHolders
#findServiceBeanDefinitionHolders(ClassPathBeanDefinitionScanner scanner, String packageToScan, BeanDefinitionRegistry registry, BeanNameGenerator beanNameGenerator) 方法,创建每个在 packageToScan 扫描到的类,对应的 BeanDefinitionHolder 对象,返回 BeanDefinitionHolder 集合。代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
//
ServiceAnnotationBeanPostProcessor.java/** * Finds a {
@link
Set
}
of {
@link
BeanDefinitionHolder BeanDefinitionHolders
}
whose bean type annotated * {
@link
Service
}
Annotation. * *
@param
scanner {
@link
ClassPathBeanDefinitionScanner
}
*
@param
packageToScan pachage to scan *
@param
registry {
@link
BeanDefinitionRegistry
}
*
@return
non-null *
@since
2.5.8 */
@SuppressWarnings("Duplicates")
private Set<BeanDefinitionHolder> findServiceBeanDefinitionHolders( ClassPathBeanDefinitionScanner scanner, String packageToScan, BeanDefinitionRegistry registry, BeanNameGenerator beanNameGenerator) {
// 获得 packageToScan 包下符合条件的
BeanDefinition 集合 Set<BeanDefinition> beanDefinitions = scanner.findCandidateComponents(packageToScan);
// 创建
BeanDefinitionHolder 集合 Set<BeanDefinitionHolder> beanDefinitionHolders = new LinkedHashSet<BeanDefinitionHolder>(beanDefinitions.size());
// 遍历 beanDefinitions 数组 for (BeanDefinition beanDefinition : beanDefinitions) { // 获得;
Bean 的名字 String beanName = beanNameGenerator.generateBeanName(beanDefinition, registry);
// 创建
BeanDefinitionHolder 对象 BeanDefinitionHolder beanDefinitionHolder = new BeanDefinitionHolder(beanDefinition, beanName);
// 添加到 beanDefinitions 中 beanDefinitionHolders.add(beanDefinitionHolder);
} return beanDefinitionHolders;
}
5.2.5 registerServiceBean
#registerServiceBean(BeanDefinitionHolder beanDefinitionHolder, BeanDefinitionRegistry registry, DubboClassPathBeanDefinitionScanner scanner) 方法,注册到 registry 中。代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
//
ServiceAnnotationBeanPostProcessor.java/** * Registers {
@link
ServiceBean
}
from new annotated {
@link
Service
}
{
@link
BeanDefinition
}
* *
@param
beanDefinitionHolder *
@param
registry *
@param
scanner *
@see
ServiceBean *
@see
BeanDefinition */
@SuppressWarnings("Duplicates")
private void registerServiceBean(BeanDefinitionHolder beanDefinitionHolder, BeanDefinitionRegistry registry, DubboClassPathBeanDefinitionScanner scanner) {
// <1.1> 解析
Bean 的类 Class<?> beanClass = resolveClass(beanDefinitionHolder);
// <1.2> 获得 @Service 注解
Service service = AnnotationUtils.findAnnotation(beanClass, Service.class);
// <1.3> 获得
Service 接口 Class<?> interfaceClass = resolveServiceInterfaceClass(beanClass, service);
// <1.4> 获得
Bean 的名字 String annotatedServiceBeanName = beanDefinitionHolder.getBeanName();
// <1.5> 创建
AbstractBeanDefinition 对象 AbstractBeanDefinition serviceBeanDefinition = buildServiceBeanDefinition(service, interfaceClass, annotatedServiceBeanName);
//
ServiceBean Bean name
// <2> 重新生成
Bean 的名字 String beanName = generateServiceBeanName(service, interfaceClass, annotatedServiceBeanName);
// <3> 校验在 scanner 中,已经存在 beanName 。若不存在,则进行注册。 if (scanner.checkCandidate(beanName, serviceBeanDefinition)) { // check duplicated candidate bean registry.registerBeanDefinition(beanName, serviceBeanDefinition); if (logger.isInfoEnabled()) { logger.info("The
BeanDefinition[" + serviceBeanDefinition + "] of ServiceBean has been registered with name : " + beanName);
}
}
else {
if (logger.isWarnEnabled()) {
logger.warn("The Duplicated BeanDefinition[" + serviceBeanDefinition + "] of ServiceBean[ bean name : " + beanName + "] was be found , Did
@DubboComponentScan
scan to same package in many times?");
}
}
}
- <1.1> 处,调用 #resolveClass(BeanDefinitionHolder beanDefinitionHolder) 方法,解析返回 Bean 的类。代码如下:
1
2
3
4
5
6
7
8
9
10
//
ServiceAnnotationBeanPostProcessor.javaprivate Class<?> resolveClass(BeanDefinitionHolder beanDefinitionHolder) {
BeanDefinition beanDefinition = beanDefinitionHolder.getBeanDefinition();
return resolveClass(beanDefinition);
}
private Class<?> resolveClass(BeanDefinition beanDefinition) {
String beanClassName = beanDefinition.getBeanClassName();
return ClassUtils.resolveClassName(beanClassName, classLoader);
}
因为 BeanDefinition 的 beanClassName 是 String 类型,所以得转换成 Class 类型。
- <1.2> 处,获得 @Service 注解。
- <1.3> 处,调用 #resolveServiceInterfaceClass(Class<?> annotatedServiceBeanClass, Service service) 方法,获得 Service 接口。代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
//
ServiceAnnotationBeanPostProcessor.java
@SuppressWarnings("Duplicates")
private Class<?> resolveServiceInterfaceClass(Class<?> annotatedServiceBeanClass, Service service) {
// 首先,从注解本身上获得
Class<?> interfaceClass = service.interfaceClass();
if (void.class.equals(interfaceClass)) {
// 一般是满足的 interfaceClass = null; // 获得 @Service 注解的 interfaceName 属性。
String interfaceClassName = service.interfaceName();
// 如果存在,获得其对应的类 if (StringUtils.hasText(interfaceClassName)) { if (ClassUtils.isPresent(interfaceClassName, classLoader)) { interfaceClass =
ClassUtils.resolveClassName(interfaceClassName, classLoader);
}
}
}
// <X>【一般情况下,使用这个】获得不到,则从被注解的类上获得其实现的首个接口 if (interfaceClass == null) {
Class<?>[] allInterfaces = annotatedServiceBeanClass.getInterfaces();
if (allInterfaces.length > 0) {
interfaceClass = allInterfaces[0];
}
}
Assert.notNull(interfaceClass, "
@Service
interfaceClass() or interfaceName() or interface class must be present!");
Assert.isTrue(interfaceClass.isInterface(), "The type that was annotated
@Service
is not an interface!");
return interfaceClass;
}
虽然代码比较长,但是重点看
- <1.4> 处,获得 Bean 的名字。
- <1.5> 处,调用 #buildServiceBeanDefinition(Service service, Class<?> interfaceClass, String annotatedServiceBeanName) 方法,创建 AbstractBeanDefinition 对象。代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
//
ServiceAnnotationBeanPostProcessor.java
@SuppressWarnings("Duplicates")
private AbstractBeanDefinition buildServiceBeanDefinition(Service service, Class<?> interfaceClass, String annotatedServiceBeanName) {
// 创建
BeanDefinitionBuilder 对象 BeanDefinitionBuilder builder = BeanDefinitionBuilder.rootBeanDefinition(ServiceBean.class);
// 获得
AbstractBeanDefinition 对象 AbstractBeanDefinition beanDefinition = builder.getBeanDefinition();
// 获得
MutablePropertyValues 属性。后续 ,通过向它添加属性,设置到 BeanDefinition 中,即 Service Bean 中。 MutablePropertyValues propertyValues = beanDefinition.getPropertyValues();
// <X> 创建
AnnotationPropertyValuesAdapter 对象,添加到 propertyValues 中。
// 此处,是将注解上的属性,设置到 propertyValues 中
String[] ignoreAttributeNames = of("provider", "monitor", "application", "module", "registry", "protocol", "interface", "interfaceName");
// 忽略的属性,下面进行单独设置。 propertyValues.addPropertyValues(new
AnnotationPropertyValuesAdapter(service, environment, ignoreAttributeNames));
//
References "ref" property to annotated-
@Service
Bean
// 设置 ref 属性指向的
Service Bean 名字 addPropertyReference(builder, "ref", annotatedServiceBeanName);
//
Set interface 设置 Service 接口类全类名 builder.addPropertyValue("interface", interfaceClass.getName());
/** * Add {
@link
org.apache.dubbo.config.ProviderConfig
}
Bean reference * * 添加 provider 属性对应的 ProviderConfig Bean 对象 */ String providerConfigBeanName = service.provider();
if (StringUtils.hasText(providerConfigBeanName)) {
addPropertyReference(builder, "provider", providerConfigBeanName);
}
/** * Add {
@link
org.apache.dubbo.config.MonitorConfig
}
Bean reference * * 添加 monitor 属性对应的 MonitorConfig Bean 对象 */ String monitorConfigBeanName = service.monitor();
if (StringUtils.hasText(monitorConfigBeanName)) {
addPropertyReference(builder, "monitor", monitorConfigBeanName);
}
/** * Add {
@link
org.apache.dubbo.config.ApplicationConfig
}
Bean reference * * 添加 application 属性对应的 ApplicationConfig Bean 对象 */ String applicationConfigBeanName = service.application();
if (StringUtils.hasText(applicationConfigBeanName)) {
addPropertyReference(builder, "application", applicationConfigBeanName);
}
/** * Add {
@link
org.apache.dubbo.config.ModuleConfig
}
Bean reference * * 添加 module 属性对应的 ModuleConfig Bean 对象 */ String moduleConfigBeanName = service.module();
if (StringUtils.hasText(moduleConfigBeanName)) {
addPropertyReference(builder, "module", moduleConfigBeanName);
}
/** * Add {
@link
org.apache.dubbo.config.RegistryConfig
}
Bean reference * * 添加 registries 属性对应的 RegistryConfig Bean 数组(一个或多个) */ String[] registryConfigBeanNames = service.registry();
List<RuntimeBeanReference> registryRuntimeBeanReferences = toRuntimeBeanReferences(registryConfigBeanNames);
if (!registryRuntimeBeanReferences.isEmpty()) {
builder.addPropertyValue("registries", registryRuntimeBeanReferences);
}
/** * Add {
@link
org.apache.dubbo.config.ProtocolConfig
}
Bean reference * * 添加 protocols 属性对应的 ProtocolConfig Bean 数组(一个或多个) */ String[] protocolConfigBeanNames = service.protocol();
List<RuntimeBeanReference> protocolRuntimeBeanReferences = toRuntimeBeanReferences(protocolConfigBeanNames);
if (!protocolRuntimeBeanReferences.isEmpty()) {
builder.addPropertyValue("protocols", protocolRuntimeBeanReferences);
}
return builder.getBeanDefinition();
}
//
RuntimeBeanReference ,在解析到依赖的Bean的时侯,解析器会依据依赖bean的name创建一个RuntimeBeanReference对像,将这个对像放入BeanDefinition的MutablePropertyValues中。
// 此处,和上面不太一样的原因,因为是多个@SuppressWarnings("Duplicates")private
ManagedList<RuntimeBeanReference> toRuntimeBeanReferences(String... beanNames) {
ManagedList<RuntimeBeanReference> runtimeBeanReferences = new ManagedList<RuntimeBeanReference>();
if (!ObjectUtils.isEmpty(beanNames)) {
for (String beanName : beanNames) {
// 解析真正的
Bean 名字,如果有占位符的话 String resolvedBeanName = environment.resolvePlaceholders(beanName);
runtimeBeanReferences.add(new RuntimeBeanReference(resolvedBeanName));
}
}
return runtimeBeanReferences;
}
// 添加属性值是引用类型private void addPropertyReference(BeanDefinitionBuilder builder,
String propertyName, String beanName) {
String resolvedBeanName = environment.resolvePlaceholders(beanName);
builder.addPropertyReference(propertyName, resolvedBeanName);
}
- 比较冗长,顺着往下看即可。
-
处,创建 AnnotationPropertyValuesAdapter 对象,添加到 `propertyValues` 中。此处,是将注解上的属性,设置到 `propertyValues` 中。也就是说,注解上的属性,自然的能够设置到后续创建的 Service Bean 的对象中。 - 举个例子,如果说
@Service(version="1.0.0"),那么这个版本号(version),就可以设置到 Dubbo Service Bean 中去了。 - 关于
org.apache.dubbo.config.spring.beans.factory.annotation.AnnotationPropertyValuesAdapter类,就是上述的用途,比较简单,胖友点击 链接 查看即可。
- 举个例子,如果说
- <2> 处,调用 #generateServiceBeanName(Service service, Class<?> interfaceClass, String annotatedServiceBeanName) 方法,重新生成 Bean 的名字。代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
//
ServiceAnnotationBeanPostProcessor.javaprivate String generateServiceBeanName(Service service, Class<?> interfaceClass, String annotatedServiceBeanName) {
ServiceBeanNameBuilder builder = ServiceBeanNameBuilder.create(service, interfaceClass, environment);
return builder.build();
}
//
ServiceBeanNameBuilder.javaprivate static final String SEPARATOR = ":";
private final String interfaceClassName;
private final Environment environment;
//
Optionalprivate String version;
private String group;
//
ServiceBean:${
interfaceClassName
}
:${
version
}
:${
group
}
public String build() {
StringBuilder beanNameBuilder = new StringBuilder("ServiceBean");
//
Required append(beanNameBuilder, interfaceClassName);
//
Optional append(beanNameBuilder, version);
append(beanNameBuilder, group);
//
Build String rawBeanName = beanNameBuilder.toString();
//
Resolve placeholders return environment.resolvePlaceholders(rawBeanName);
}
private static void append(StringBuilder builder, String value) {
if (StringUtils.hasText(value)) {
builder.append(SEPARATOR).append(value);
}
}
整个逻辑,有点长长滴。胖友辛苦上下滑动,在瞅瞅。
5.3 ReferenceAnnotationBeanPostProcessor
org.apache.dubbo.config.spring.beans.factory.annotation.ReferenceAnnotationBeanPostProcessor ,继承 AnnotationInjectedBeanPostProcessor 抽象类,实现 ApplicationContextAware、ApplicationListener 接口,扫描 @Reference 注解的类,创建对应的 Spring BeanDefinition 对象,从而创建 Dubbo Reference Bean 对象。
虽然 org.apache.dubbo.config.spring.beans.factory.annotation.AnnotationInjectedBeanPostProcessor 放在 Dubbo 项目中,但是是 clone 自 https://github.com/alibaba/spring-context-support/blob/1.0.2/src/main/java/com/alibaba/spring/beans/factory/annotation/AnnotationInjectedBeanPostProcessor.java 类。所以呢,我们先不深究这个类,只要知道如下:
- 英文:Abstract generic {@link BeanPostProcessor} implementation for customized annotation that annotated injected-object.
- 中文:BeanPostProcessor 的抽象实现类,用于支持使用自定义注解,注入对象的属性。
- 此时,ReferenceAnnotationBeanPostProcessor 实现的就是 支持 @Reference 注解的属性注入。
相对来说,本节的 ReferenceAnnotationBeanPostProcessor ,会比上一节的 ServiceAnnotationBeanPostProcessor 复杂蛮多~ SO ,保持耐心哈。
5.3.1 构造方法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
//
ReferenceAnnotationBeanPostProcessor.java/** * The bean name of {
@link
ReferenceAnnotationBeanPostProcessor
}
*/public static final String BEAN_NAME = "referenceAnnotationBeanPostProcessor";
/** * Cache size */private static final int CACHE_SIZE = Integer.getInteger(BEAN_NAME + ".cache.size", 32);
/** * ReferenceBean 缓存 Map * * KEY:Reference Bean 的名字 */private final ConcurrentMap<String, ReferenceBean<?>> referenceBeanCache = new ConcurrentHashMap<String, ReferenceBean<?>>(CACHE_SIZE);
/** * ReferenceBeanInvocationHandler 缓存 Map * * KEY:Reference Bean 的名字 */private final ConcurrentHashMap<String, ReferenceBeanInvocationHandler> localReferenceBeanInvocationHandlerCache = new ConcurrentHashMap<String, ReferenceBeanInvocationHandler>(CACHE_SIZE);
/** * 使用属性进行注入的
@Reference
Bean 的缓存 Map * * 一般情况下,使用这个 */private final ConcurrentMap<InjectionMetadata.InjectedElement, ReferenceBean<?>> injectedFieldReferenceBeanCache = new ConcurrentHashMap<InjectionMetadata.InjectedElement, ReferenceBean<?>>(CACHE_SIZE);
/** * 使用方法进行注入的
@Reference
Bean 的缓存 Map */private final ConcurrentMap<InjectionMetadata.InjectedElement, ReferenceBean<?>> injectedMethodReferenceBeanCache = new ConcurrentHashMap<InjectionMetadata.InjectedElement, ReferenceBean<?>>(CACHE_SIZE);
private ApplicationContext applicationContext;```
- 具体的每个变量的时候,结合下面来看。
### 5.3.2 doGetInjectedBean
实现 #doGetInjectedBean(Reference reference, Object bean, String beanName, Class<?> injectedType, InjectionMetadata.InjectedElement injectedElement) 方法,获得要注入的 @Reference Bean 。代码如下:
```java
//
ReferenceAnnotationBeanPostProcessor.java
@Overrideprotected
Object doGetInjectedBean(Reference reference, Object bean, String beanName, Class<?> injectedType, InjectionMetadata.InjectedElement injectedElement) throws Exception {
// <1> 获得
Reference Bean 的名字 String referencedBeanName = buildReferencedBeanName(reference, injectedType);
// <2> 创建
ReferenceBean 对象 ReferenceBean referenceBean = buildReferenceBeanIfAbsent(referencedBeanName, reference, injectedType, getClassLoader());
// <3> 缓存到 injectedFieldReferenceBeanCache or injectedMethodReferenceBeanCache 中 cacheInjectedReferenceBean(referenceBean, injectedElement); // <4> 创建
Proxy 代理对象 return buildProxy(referencedBeanName, referenceBean, injectedType);
}
- <1> 处,调用 #buildReferencedBeanName(Reference reference, Class<?> injectedType) 方法,获得 Reference Bean 的名字。代码如下:
1
2
3
4
5
6
7
//
ReferenceAnnotationBeanPostProcessor.javaprivate String buildReferencedBeanName(Reference reference, Class<?> injectedType) {
// 创建
Service Bean 的名字 ServiceBeanNameBuilder builder = ServiceBeanNameBuilder.create(reference, injectedType, getEnvironment());
return getEnvironment().resolvePlaceholders(builder.build());
// 这里,貌似重复解析占位符了。不过没啥影响~}
实际上,使用的就是 ServiceBeanNameBuilder 的逻辑,即和 Dubbo Service Bean 的名字,是 同一套。当然,这个也非常合理~
- <2> 处,调用 #buildReferenceBeanIfAbsent(String referencedBeanName, Reference reference, Class<?> referencedType, ClassLoader classLoader) 方法,创建(获得) ReferenceBean 对象。代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
//
ReferenceAnnotationBeanPostProcessor.javaprivate ReferenceBean buildReferenceBeanIfAbsent(String referencedBeanName, Reference reference, Class<?> referencedType, ClassLoader classLoader)throws Exception {
// 首先,从 referenceBeanCache 缓存中,获得 referencedBeanName 对应的
ReferenceBean 对象 ReferenceBean<?> referenceBean = referenceBeanCache.get(referencedBeanName);
// 然后,如果不存在,则进行创建。然后,添加到 referenceBeanCache 缓存中。 if (referenceBean == null) {
ReferenceBeanBuilder beanBuilder = ReferenceBeanBuilder .create(reference, classLoader, applicationContext) .interfaceClass(referencedType);
referenceBean = beanBuilder.build();
referenceBeanCache.put(referencedBeanName, referenceBean);
}
return referenceBean;
}
其中,会使用 ReferenceBeanBuilder 类,构建 ReferenceBean 对象。关于它,我们稍后在 「5.3.4 ReferenceBeanBuilder」 来瞅瞅。实际上,和上面 ServiceBean 的构建,也差不了太多。
- <3> 处,调用 #cacheInjectedReferenceBean(String referencedBeanName, Reference reference, Class<?> referencedType, ClassLoader classLoader) 方法,缓存到 injectedFieldReferenceBeanCache or injectedMethodReferenceBeanCache 中。代码如下:
1
2
3
4
5
6
7
8
9
10
11
//
ReferenceAnnotationBeanPostProcessor.javaprivate void cacheInjectedReferenceBean(ReferenceBean referenceBean, InjectionMetadata.InjectedElement injectedElement) {
if (injectedElement.getMember() instanceof Field) {
injectedFieldReferenceBeanCache.put(injectedElement, referenceBean);
}
else if (injectedElement.getMember() instanceof Method) {
injectedMethodReferenceBeanCache.put(injectedElement, referenceBean);
}
}
- <4> 处,调用 #buildProxy(String referencedBeanName, ReferenceBean referenceBean, Class<?> injectedType) 方法,创建 Proxy 代理对象。代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
// ReferenceAnnotationBeanPostProcessor.java
private Object buildProxy(String referencedBeanName, ReferenceBean referenceBean, Class<?> injectedType) {
InvocationHandler handler = buildInvocationHandler(referencedBeanName, referenceBean);
return Proxy.newProxyInstance(getClassLoader(), new Class[]{injectedType}, handler);
}
private InvocationHandler buildInvocationHandler(String referencedBeanName, ReferenceBean referenceBean) {
// 首先,从 localReferenceBeanInvocationHandlerCache 缓存中,获得 ReferenceBeanInvocationHandler 对象
ReferenceBeanInvocationHandler handler = localReferenceBeanInvocationHandlerCache.get(referencedBeanName);
// 然后,如果不存在,则创建 ReferenceBeanInvocationHandler 对象
if (handler == null) {
handler = new ReferenceBeanInvocationHandler(referenceBean);
}
// <X> 之后,根据引用的 Dubbo 服务是远程的还是本地的,做不同的处理。
// 【本地】判断如果 applicationContext 中已经初始化,说明是本地的 @Service Bean ,则添加到 localReferenceBeanInvocationHandlerCache 缓存中。
// 等到本地的 @Service Bean 暴露后,再进行初始化。
if (applicationContext.containsBean(referencedBeanName)) { // Is local @Service Bean or not ?
// ReferenceBeanInvocationHandler's initialization has to wait for current local @Service Bean has been exported.
localReferenceBeanInvocationHandlerCache.put(referencedBeanName, handler);
// 【远程】判断若果 applicationContext 中未初始化,说明是远程的 @Service Bean 对象,则立即进行初始化
} else {
// Remote Reference Bean should initialize immediately
handler.init();
}
return handler;
}
- 比较复杂的是,
处,根据引用的 Dubbo 服务是远程的还是本地的,做不同的处理。为什么呢? - 远程的 Dubbo 服务,理论来说(不考虑对方挂掉的情况),是已经存在,此时可以进行加载引用。
- 本地的 Dubbo 服务,此时并未暴露,则先添加到
localReferenceBeanInvocationHandlerCache中进行缓存。等后续的,通过 Spring 事件监听的功能,进行实现。详细的,我们在 「5.3.3 onApplicationEvent」 中会看到。
- ReferenceBeanInvocationHandler ,是 ReferenceAnnotationBeanPostProcessor 的内部静态类,实现 Dubbo InvocationHandler 接口,代码如下: ```
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
//
ReferenceAnnotationBeanPostProcessor#ReferenceBeanInvocationHandler.javaprivate static class ReferenceBeanInvocationHandler implements InvocationHandler {
/** * ReferenceBean 对象 */ private final ReferenceBean referenceBean;
/** * Bean 对象 */ private Object bean;
private ReferenceBeanInvocationHandler(ReferenceBean referenceBean) {
this.referenceBean = referenceBean;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 调用 bean 的对应的方法 return method.invoke(bean, args); } // 通过初始化方法,可以获得 `ReferenceBean.ref` private void init()
{
this.bean = referenceBean.get();
}
}
* 重心在于 `#init()` 方法,可以调用 `ReferenceBean#get()` 方法,进行引用的 Bean 的初始化,最后返回引用 `ref` 。
### 5.3.3 onApplicationEvent
实现 #onApplicationEvent(ApplicationEvent event) 方法,代码如下:
```java
//
ReferenceAnnotationBeanPostProcessor.java
@Overridepublic
void onApplicationEvent(ApplicationEvent event) {
if (event instanceof ServiceBeanExportedEvent) {
onServiceBeanExportEvent((ServiceBeanExportedEvent) event);
}
else if (event instanceof ContextRefreshedEvent) {
onContextRefreshedEvent((ContextRefreshedEvent) event);
}
}
private void onServiceBeanExportEvent(ServiceBeanExportedEvent event) {
// 获得
ServiceBean 对象 ServiceBean serviceBean = event.getServiceBean();
// 初始化对应的
ReferenceBeanInvocationHandler initReferenceBeanInvocationHandler(serviceBean);
}
private void initReferenceBeanInvocationHandler(ServiceBean serviceBean) {
String serviceBeanName = serviceBean.getBeanName();
//
Remove ServiceBean when it's exported
// 从 localReferenceBeanInvocationHandlerCache 缓存中,移除
ReferenceBeanInvocationHandler handler = localReferenceBeanInvocationHandlerCache.remove(serviceBeanName);
//
Initialize
// 执行初始化 if (handler != null)
{
handler.init();
}}private void onContextRefreshedEvent(ContextRefreshedEvent event)
{
}
}
- 重点在于处理 ServiceBeanExportedEvent 事件。处理时,如果判断 「5.2.2 doGetInjectedBean」 localReferenceBeanInvocationHandlerCache 中存在 ReferenceBeanInvocationHandler 对象,说明有它未初始化。后续,调用 ReferenceBeanInvocationHandler#init() 方法,从而完成。这块,胖友结合 一起,是不是就明白了。
- 在 ServiceBean 暴露服务完成后,会发布 ServiceBeanExportedEvent 事件。代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
//
ServiceBean.javaprivate ApplicationEventPublisher applicationEventPublisher;
/** *
@since
2.6.5 */
@Overridepublic
void export() {
// 暴露服务 super.export(); //
Publish ServiceBeanExportedEvent
// 发布事件 publishExportEvent();}/** * @since 2.6.5 */private void publishExportEvent()
{
// 创;
}
// 创建
ServiceBeanExportedEvent 对象 ServiceBeanExportedEvent exportEvent = new ServiceBeanExportedEvent(this);
// 发布事件 applicationEventPublisher.publishEvent(exportEvent);}
- org.apache.dubbo.config.spring.context.event.ServiceBeanExportedEvent ,Service Bean 暴露完成事件。代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
//
BeanExportedEvent.java/** * A {
@link
ApplicationEvent
}
after {
@link
ServiceBean
}
{
@link
ServiceBean#export() export
}
invocation * *
@see
ApplicationEvent *
@see
ApplicationListener *
@see
ServiceBean *
@since
2.6.5 */public class ServiceBeanExportedEvent extends ApplicationEvent {
/** * Create a new ApplicationEvent. * *
@param
serviceBean {
@link
ServiceBean
}
bean */ public ServiceBeanExportedEvent(ServiceBean serviceBean) {
super(serviceBean);
}
/** * Get {
@link
ServiceBean
}
instance * *
@return
non-null */ public ServiceBean getServiceBean() {
return (ServiceBean) super.getSource();
}
}
5.3.4 ReferenceBeanBuilder
org.apache.dubbo.config.spring.beans.factory.annotation.ReferenceBeanBuilder ,继承 AbstractAnnotationConfigBeanBuilder 抽象类,ReferenceBean 的构建器。
考虑到 ReferenceBeanBuilder 类,就是 #build() 方法,我们就直接结合 AbstractAnnotationConfigBeanBuilder 抽象类,一起写了。
5.3.4.1 构造方法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
//
AbstractAnnotationConfigBeanBuilder.javaabstract class AbstractAnnotationConfigBeanBuilder<A extends Annotation, B extends AbstractInterfaceConfig> {
/** * 注解 */ protected final A annotation;
protected final ApplicationContext applicationContext;
protected final ClassLoader classLoader;
/** * Bean 对象 */ protected Object bean;
/** * 接口 */ protected Class<?> interfaceClass;
protected AbstractAnnotationConfigBeanBuilder(A annotation, ClassLoader classLoader, ApplicationContext applicationContext) {
Assert.notNull(annotation, "The Annotation must not be null!");
Assert.notNull(classLoader, "The ClassLoader must not be null!");
Assert.notNull(applicationContext, "The ApplicationContext must not be null!");
this.annotation = annotation;
this.applicationContext = applicationContext;
this.classLoader = classLoader;
}
}
//
ReferenceBeanBuilder.javaclass ReferenceBeanBuilder extends AbstractAnnotationConfigBeanBuilder<Reference, ReferenceBean> {
private ReferenceBeanBuilder(Reference annotation, ClassLoader classLoader, ApplicationContext applicationContext) {
super(annotation, classLoader, applicationContext);
}
public static ReferenceBeanBuilder create(Reference annotation, ClassLoader classLoader, ApplicationContext applicationContext) {
return new ReferenceBeanBuilder(annotation, classLoader, applicationContext);
}
}
- 其中,泛型 A 对应 @Reference 注解,泛型 B 对应 ReferenceBean 类。
5.3.4.2 build
#build() 方法,构造泛型 B 对象。此处,就是构造 ReferenceBean 对象。代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
//
AbstractAnnotationConfigBeanBuilder.javapublic final B build() throws Exception {
// 校验依赖 checkDependencies(); // 执行构造
Bean 对象 B bean = doBuild();
// 配置
Bean 对象 configureBean(bean);
if (logger.isInfoEnabled()) {
logger.info("The bean[type:" + bean.getClass().getSimpleName() + "] has been built.");
}
return bean;
}
private void checkDependencies() {
}
/** * Builds {
@link
B Bean
}
* *
@return
{
@link
B Bean
}
*/protected abstract B doBuild();
protected void configureBean(B bean) throws Exception {
// 前置配置 preConfigureBean(annotation, bean); // 配置
RegistryConfig 属性 configureRegistryConfigs(bean);
// 配置
MonitorConfig 属性 configureMonitorConfig(bean);
// 配置
ApplicationConfig 属性 configureApplicationConfig(bean);
// 配置
ModuleConfig 属性 configureModuleConfig(bean);
// 后置配置 postConfigureBean(annotation, bean);}protected abstract void preConfigureBean(A annotation,
B bean) throws Exception;
// 抽象方法private void configureRegistryConfigs(B bean) {
String[] registryConfigBeanIds = resolveRegistryConfigBeanNames(annotation);
List<RegistryConfig> registryConfigs = BeanFactoryUtils.getBeans(applicationContext, registryConfigBeanIds, RegistryConfig.class);
bean.setRegistries(registryConfigs);
}
private void configureMonitorConfig(B bean) {
String monitorBeanName = resolveMonitorConfigBeanName(annotation);
MonitorConfig monitorConfig = BeanFactoryUtils.getOptionalBean(applicationContext, monitorBeanName, MonitorConfig.class);
bean.setMonitor(monitorConfig);
}
private void configureApplicationConfig(B bean) {
String applicationConfigBeanName = resolveApplicationConfigBeanName(annotation);
ApplicationConfig applicationConfig = BeanFactoryUtils.getOptionalBean(applicationContext, applicationConfigBeanName, ApplicationConfig.class);
bean.setApplication(applicationConfig);
}
private void configureModuleConfig(B bean) {
String moduleConfigBeanName = resolveModuleConfigBeanName(annotation);
ModuleConfig moduleConfig = BeanFactoryUtils.getOptionalBean(applicationContext, moduleConfigBeanName, ModuleConfig.class);
bean.setModule(moduleConfig);
}
protected abstract String resolveModuleConfigBeanName(A annotation);
// 抽象方法protected abstract
String resolveApplicationConfigBeanName(A annotation);
// 抽象方法protected abstract
String[] resolveRegistryConfigBeanNames(A annotation);
// 抽象方法protected abstract
String resolveMonitorConfigBeanName(A annotation);
// 抽象方法protected abstract void postConfigureBean(A annotation,
B bean) throws Exception;
// 抽象方法
- ReferenceBeanBuilder 主要对上面的抽象方法,进行具体实现。代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
//
ReferenceBeanBuilder.javastatic final String[] IGNORE_FIELD_NAMES = of("application", "module", "consumer", "monitor", "registry")
@Overrideprotected
ReferenceBean doBuild() {
// 创建
ReferenceBean 对象 return new ReferenceBean<>();
}
@SuppressWarnings("Duplicates")
@Overrideprotected
void preConfigureBean(Reference reference, ReferenceBean referenceBean) {
Assert.notNull(interfaceClass, "The interface class must set first!");
// 创建
DataBinder 对象 DataBinder dataBinder = new DataBinder(referenceBean);
//
Register CustomEditors for special fields
// 注册指定属性的自定义
Editor dataBinder.registerCustomEditor(String.class, "filter", new StringTrimmerEditor(true));
dataBinder.registerCustomEditor(String.class, "listener", new StringTrimmerEditor(true));
dataBinder.registerCustomEditor(Map.class, "parameters", new PropertyEditorSupport() {
@Override
public void setAsText(String text) throws java.lang.IllegalArgumentException {
//
Trim all whitespace String content = StringUtils.trimAllWhitespace(text);
if (!StringUtils.hasText(content)) {
//
No content , ignore directly return;
}
// replace "=" to "," content =
StringUtils.replace(content, "=", ",");
// replace ":" to "," content =
StringUtils.replace(content, ":", ",");
//
String[] to Map Map<String, String> parameters = CollectionUtils.toStringMap(commaDelimitedListToStringArray(content));
setValue(parameters);
}
}
);
//
Bind annotation attributes
// 将注解的属性,设置到 reference 中 dataBinder.bind(new
AnnotationPropertyValuesAdapter(reference, applicationContext.getEnvironment(), IGNORE_FIELD_NAMES));
}
@Overrideprotected
String resolveModuleConfigBeanName(Reference annotation) {
return annotation.module();
}
@Overrideprotected
String resolveApplicationConfigBeanName(Reference annotation) {
return annotation.application();
}
@Overrideprotected
String[] resolveRegistryConfigBeanNames(Reference annotation) {
return annotation.registry();
}
@Overrideprotected
String resolveMonitorConfigBeanName(Reference annotation) {
return annotation.monitor();
}
@Overrideprotected
void postConfigureBean(Reference annotation, ReferenceBean bean) throws Exception {
// 设置 applicationContext bean.setApplicationContext(applicationContext);
// 配置 interfaceClass configureInterface(annotation, bean);
// 配置
ConsumerConfig configureConsumerConfig(annotation, bean);
// 执行
Bean 后置属性初始化 bean.afterPropertiesSet();
}
@SuppressWarnings("Duplicates")
private void configureInterface(Reference reference, ReferenceBean referenceBean) {
// 首先,从 @Reference 获得 interfaceName 属性,从而获得 interfaceClass 类
Class<?> interfaceClass = reference.interfaceClass();
if (void.class.equals(interfaceClass)) {
interfaceClass = null;
String interfaceClassName = reference.interfaceName();
if (StringUtils.hasText(interfaceClassName)) {
if (ClassUtils.isPresent(interfaceClassName, classLoader)) {
interfaceClass = ClassUtils.resolveClassName(interfaceClassName, classLoader);
}
}
}
// 如果获得不到,则使用 interfaceClass 即可 if (interfaceClass == null)
{
interfaceClass = this.interfaceClass;
}
Assert.isTrue(interfaceClass.isInterface(), "The class of field or method that was annotated
@Reference
is not an interface!");
referenceBean.setInterface(interfaceClass);
}
private void configureConsumerConfig(Reference reference, ReferenceBean<?> referenceBean) {
// 获得
ConsumerConfig 对象 String consumerBeanName = reference.consumer();
ConsumerConfig consumerConfig = getOptionalBean(applicationContext, consumerBeanName, ConsumerConfig.class);
// 设置到 referenceBean 中 referenceBean.setConsumer(consumerConfig);}
~
写的相对简略。胖友注意看每一个的注释哈~
5.3.5 destroy
实现 #destroy() 方法,执行销毁逻辑。代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
//
ReferenceAnnotationBeanPostProcessor.java
@Overridepublic
void destroy() throws Exception {
// 父类销毁 super.destroy();
// 清空缓存 this.referenceBeanCache.clear();
this.localReferenceBeanInvocationHandlerCache.clear();
this.injectedFieldReferenceBeanCache.clear();
this.injectedMethodReferenceBeanCache.clear();
}
666. 彩蛋
比想象中的长特别特别特别多~这个还是有一些地方写的比较简略的。
本文的源码解析,对应仓库为 https://github.com/YunaiV/dubbo/tree/master-2.7.1 。
熬夜快乐~

