dubbo的Reference注解是如何生效的

dubbo的Reference注解实现原理 中提到,@Reference 注解用于实现 RPC client 代理的自动注入,这是通过 ReferenceAnnotationBeanPostProcessor 来实现的。若要让其生效,还需要在这之前将其注册到 BeanFactory 中。

通常配置 spring 的方式有 XML 形式、java 注解形式,那么注册 ReferenceAnnotationBeanPostProcessor 的方式也分别有 XML 形式配置、java 注解形式配置。

整体流程

通常情况下,往 ApplicationContext 类型的容器中注册 BeanPostProcessor 的过程主要包括如下两个步骤:

  1. BeanDefinitonRegistry 中注册 BeanPostProcessorBeanDefinition 定义
  2. BeanFactory 中获取 BeanPostProcessor 类型的 Bean,将其注册到 BeanFactory 的后处理器中

其中第一步需要使用者自己处理,spring 会自动完成第二步操作。

注册 BeanDefinition

ReferenceAnnotationBeanPostProcessorBeanDefintion 的形式注册到 BeanDefinitionRegistry 中。

XML 方式

使用方式

如下是一个使用 XML 方式的配置:

1
2
3
4
5
6
7
8
9
10
11
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:dubbo="http://dubbo.apache.org/schema/dubbo"
xmlns="http://www.springframework.org/schema/beans"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd
http://dubbo.apache.org/schema/dubbo http://dubbo.apache.org/schema/dubbo/dubbo.xsd">

<dubbo:application name="annotation-consumer"/>
<dubbo:registry address="127.0.0.1:4548"/>
<dubbo:annotation package="org.apache.dubbo.config.spring.annotation.consumer"/>

</beans>

相关配置

其中我们需要关注的配置项是:

1
<dubbo:annotation package="org.apache.dubbo.config.spring.annotation.consumer"/>

它表示要开启注解的方式,这样就支持 @Reference 注解的自动注入。

它是如何生效的

上面的 XML 中使用的是自定义的 namespace http://dubbo.apache.org/schema/dubbo,要对它进行解析处理,需要注册对应的 NamespaceHandler

Dubbo 在 class path 下的 META-INF 文件夹中新增了 handlers 配置文件 spring.handlers ,如下图所示

image-20200418161749767

在该文件中配置了 namespace 对应的 NamespaceHandler,文件内容如下(注意 : 需要进行转义):

1
http\://dubbo.apache.org/schema/dubbo=org.apache.dubbo.config.spring.schema.DubboNamespaceHandler

在解析 xml 时,spring 会通过 namespaceUri 查找对应的 NamespaceHandler 来解析 xml 元素。它的主要思路是:获取 namespaceUriNamespaceHandler 的映射关系,然后根据 namespaceUri 找到对应的 NamespaceHandler 类名,进行初始化并返回,相关代码如下:

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
public NamespaceHandler resolve(String namespaceUri) {
// URI -> NamespaceHandler的实例或类名
Map<String, Object> handlerMappings = getHandlerMappings();

// 根据 namespaceUri 获取 handler
Object handlerOrClassName = handlerMappings.get(namespaceUri);

if (handlerOrClassName == null) {
return null;
}
// 取到的是实例
else if (handlerOrClassName instanceof NamespaceHandler) {
return (NamespaceHandler) handlerOrClassName;
}
// 取到的是类名
else {
String className = (String) handlerOrClassName;
try {
Class<?> handlerClass = ClassUtils.forName(className, this.classLoader);
if (!NamespaceHandler.class.isAssignableFrom(handlerClass)) {
throw new FatalBeanException("Class [" + className + "] for namespace [" + namespaceUri +
"] does not implement the [" + NamespaceHandler.class.getName() + "] interface");
}

// 实例化
NamespaceHandler namespaceHandler = (NamespaceHandler) BeanUtils.instantiateClass(handlerClass);

// 初始化
namespaceHandler.init();

// 放到 map 中
// 下次获取到的就是实例,而不是 class name
handlerMappings.put(namespaceUri, namespaceHandler);

return namespaceHandler;
}
catch (ClassNotFoundException ex) {
throw new FatalBeanException("Could not find NamespaceHandler class [" + className +
"] for namespace [" + namespaceUri + "]", ex);
}
catch (LinkageError err) {
throw new FatalBeanException("Unresolvable class definition for NamespaceHandler class [" +
className + "] for namespace [" + namespaceUri + "]", err);
}
}
}

注意到它是通过 getHandlerMappings 获取的 namespaceUriNamespaceHandler 的映射关系,第一次调用该方法时会从加载并解析 META-INF/spring.handlers ,将映射关系保存到 handlerMappings

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
public static final String DEFAULT_HANDLER_MAPPINGS_LOCATION = "META-INF/spring.handlers";

public DefaultNamespaceHandlerResolver() {
this(null, DEFAULT_HANDLER_MAPPINGS_LOCATION);
}

private Map<String, Object> getHandlerMappings() {
Map<String, Object> handlerMappings = this.handlerMappings;
if (handlerMappings == null) {
synchronized (this) {
handlerMappings = this.handlerMappings;
if (handlerMappings == null) {
if (logger.isTraceEnabled()) {
logger.trace("Loading NamespaceHandler mappings from [" + this.handlerMappingsLocation + "]");
}
try {
// 加载HandlerMapping配置信息
Properties mappings =
PropertiesLoaderUtils.loadAllProperties(this.handlerMappingsLocation, this.classLoader);
if (logger.isTraceEnabled()) {
logger.trace("Loaded NamespaceHandler mappings: " + mappings);
}

// 初始化HandlerMapping
handlerMappings = new ConcurrentHashMap<>(mappings.size());
CollectionUtils.mergePropertiesIntoMap(mappings, handlerMappings);

// 赋值
this.handlerMappings = handlerMappings;
}
catch (IOException ex) {
throw new IllegalStateException(
"Unable to load NamespaceHandler mappings from location [" + this.handlerMappingsLocation + "]", ex);
}
}
}
}
return handlerMappings;
}

DubboNamespaceHandler的处理

接下来看下 DubboNamespaceHandler 是如何处理 xml 中的配置的。DubboNamespaceHandler 继承自 NamespaceHandlerSupport ,主要实现了 NamespaceHandler 接口的 init 方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public void init() {
registerBeanDefinitionParser("application", new DubboBeanDefinitionParser(ApplicationConfig.class, true));
registerBeanDefinitionParser("module", new DubboBeanDefinitionParser(ModuleConfig.class, true));
registerBeanDefinitionParser("registry", new DubboBeanDefinitionParser(RegistryConfig.class, true));
registerBeanDefinitionParser("config-center", new DubboBeanDefinitionParser(ConfigCenterBean.class, true));
registerBeanDefinitionParser("metadata-report", new DubboBeanDefinitionParser(MetadataReportConfig.class, true));
registerBeanDefinitionParser("monitor", new DubboBeanDefinitionParser(MonitorConfig.class, true));
registerBeanDefinitionParser("metrics", new DubboBeanDefinitionParser(MetricsConfig.class, true));
registerBeanDefinitionParser("provider", new DubboBeanDefinitionParser(ProviderConfig.class, true));
registerBeanDefinitionParser("consumer", new DubboBeanDefinitionParser(ConsumerConfig.class, true));
registerBeanDefinitionParser("protocol", new DubboBeanDefinitionParser(ProtocolConfig.class, true));
registerBeanDefinitionParser("service", new DubboBeanDefinitionParser(ServiceBean.class, true));
registerBeanDefinitionParser("reference", new DubboBeanDefinitionParser(ReferenceBean.class, false));
registerBeanDefinitionParser("annotation", new AnnotationBeanDefinitionParser());
}

在这里为每一个 XML 配置项注册了对应的 parser,其中 annotation 对应的 parser 为 AnnotationBeanDefinitionParser。这样 spring 在遇到如下配置时,会将其解析工作交给 AnnotationBeanDefinitionParser

1
<dubbo:annotation package="org.apache.dubbo.config.spring.annotation.consumer"/>

AnnotationBeanDefinitionParser解析

如上所述,AnnotationBeanDefinitionParser 用于解析 XML 中的 annotation 配置。它的主要功能是:

  1. 解析 package 配置,注册到该配置项对应的 BeanDefinition
  2. 注册 ReferenceAnnotationBeanPostProcessor
1
2
3
4
5
6
7
8
9
10
protected void doParse(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) {
// 1. set package
String packageToScan = element.getAttribute("package");
String[] packagesToScan = trimArrayElements(commaDelimitedListToStringArray(packageToScan));
builder.addConstructorArgValue(packagesToScan);
builder.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);

// 2. Registers ReferenceAnnotationBeanPostProcessor
registerReferenceAnnotationBeanPostProcessor(parserContext.getRegistry());
}

ReferenceAnnotationBeanPostProcessor 的 BeanDefinition 注册实现

1
2
3
4
5
6
7
8
9
BeanRegistrar.registerInfrastructureBean(registry,
ReferenceAnnotationBeanPostProcessor.BEAN_NAME, ReferenceAnnotationBeanPostProcessor.class);

// 内部逻辑
if (!beanDefinitionRegistry.containsBeanDefinition(beanName)) {
RootBeanDefinition beanDefinition = new RootBeanDefinition(beanType);
beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
beanDefinitionRegistry.registerBeanDefinition(beanName, beanDefinition);
}

java 注解方式

这是通过 spring 的 ImportBeanDefinitionRegistrar 扩展实现的。dubbo 提供了一个 DubboComponentScanRegistrar 类,它实现了 ImportBeanDefinitionRegistrar 接口,在这里完成了 ReferenceAnnotationBeanPostProcessor 的注册

1
2
3
4
5
6
7
8
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {

Set<String> packagesToScan = getPackagesToScan(importingClassMetadata);
registerServiceAnnotationBeanPostProcessor(packagesToScan, registry);

// 注册 ReferenceAnnotationBeanPostProcessor
registerReferenceAnnotationBeanPostProcessor(registry);
}

相关注册代码如下

1
2
3
4
5
private void registerReferenceAnnotationBeanPostProcessor(BeanDefinitionRegistry registry) {
// Register @Reference Annotation Bean Processor
BeanRegistrar.registerInfrastructureBean(registry,
ReferenceAnnotationBeanPostProcessor.BEAN_NAME, ReferenceAnnotationBeanPostProcessor.class);
}

ImportBeanDefinitionRegistrar 是如何生效的

ApplicationContext 进行 refresh 时,处理 BeanFactory 的最后一步是BeanFactoryPostProcessor。在这一步会对所有的 BeanDefinitionRegistryPostProcessor 进行回调。

在这里需要提到一个后处理器是 ConfigurationClassPostProcessor,它负责处理所有的 Configuration 类,包括 ImportBeanDefinitionRegistrar 类的回调。

ConfigurationClassPostProcessor 的注册

与 xml 类型的 bean 通过 XmlBeanDefinitionReader 解析类似,annotation 类型的 bean 通过 AnnotatedBeanDefinitionReader 进行解析。AnnotatedBeanDefinitionReader 在构造时会注册一些配置处理器,其中一个就是 ConfigurationClassPostProcessor

1
2
3
4
5
if (!registry.containsBeanDefinition(CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME)) {
RootBeanDefinition def = new RootBeanDefinition(ConfigurationClassPostProcessor.class);
def.setSource(source);
beanDefs.add(registerPostProcessor(registry, def, CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME));
}

ConfigurationClassPostProcessor 的处理

解析 ImportBeanDefinitionRegistrar 配置

上面提到 ConfigurationClassPostProcessor 实现了 BeanDefinitionRegistryPostProcessor,它的 postProcessBeanDefinitionRegistry 方法如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
int registryId = System.identityHashCode(registry);
if (this.registriesPostProcessed.contains(registryId)) {
throw new IllegalStateException(
"postProcessBeanDefinitionRegistry already called on this post-processor against " + registry);
}
if (this.factoriesPostProcessed.contains(registryId)) {
throw new IllegalStateException(
"postProcessBeanFactory already called on this post-processor against " + registry);
}
this.registriesPostProcessed.add(registryId);

processConfigBeanDefinitions(registry);
}

其中会调用 ConfigurationClassParser 解析配置类

1
2
3
4
5
6
7
8
9
10
// Parse each @Configuration class
ConfigurationClassParser parser = new ConfigurationClassParser(
this.metadataReaderFactory, this.problemReporter, this.environment,
this.resourceLoader, this.componentScanBeanNameGenerator, registry);

Set<BeanDefinitionHolder> candidates = new LinkedHashSet<>(configCandidates);
Set<ConfigurationClass> alreadyParsed = new HashSet<>(configCandidates.size());
do {
parser.parse(candidates);
parser.validate();

ConfigurationClassParser 会解析配置类上的各种注解,包括 @ComponentScan@Import

1
2
// Process any @Import annotations
processImports(configClass, sourceClass, getImports(sourceClass), true);

如果是 ImportBeanDefinitionRegistrar 的子类,则将其添加到 ConfigurationClass

1
2
3
4
5
6
7
8
9
10
11
if (candidate.isAssignable(ImportBeanDefinitionRegistrar.class)) {
// Candidate class is an ImportBeanDefinitionRegistrar ->
// delegate to it to register additional bean definitions
Class<?> candidateClass = candidate.loadClass();
ImportBeanDefinitionRegistrar registrar =
BeanUtils.instantiateClass(candidateClass, ImportBeanDefinitionRegistrar.class);
ParserStrategyUtils.invokeAwareMethods(
registrar, this.environment, this.resourceLoader, this.registry);
// 注册ImportBeanDefinitionRegistrar到configClass中
configClass.addImportBeanDefinitionRegistrar(registrar, currentSourceClass.getMetadata());
}
注册和回调 ImportBeanDefinitionRegistrar

解析完 ImportBeanDefinitionRegistrar 配置到 ConfigurationClass 之后,接下来就需要从中读取配置并注册相关的 BeanDefintion。这一步是交给 ConfigurationClassBeanDefinitionReader 来处理的

1
2
3
4
5
6
7
// Read the model and create bean definitions based on its content
if (this.reader == null) {
this.reader = new ConfigurationClassBeanDefinitionReader(
registry, this.sourceExtractor, this.resourceLoader, this.environment,
this.importBeanNameGenerator, parser.getImportRegistry());
}
this.reader.loadBeanDefinitions(configClasses);

它会从 ConfigurationClass 中取出前面解析到的 ImportBeanDefinitionRegistrar

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
private void loadBeanDefinitionsForConfigurationClass(
ConfigurationClass configClass, TrackedConditionEvaluator trackedConditionEvaluator) {

if (trackedConditionEvaluator.shouldSkip(configClass)) {
String beanName = configClass.getBeanName();
if (StringUtils.hasLength(beanName) && this.registry.containsBeanDefinition(beanName)) {
this.registry.removeBeanDefinition(beanName);
}
this.importRegistry.removeImportingClass(configClass.getMetadata().getClassName());
return;
}

if (configClass.isImported()) {
registerBeanDefinitionForImportedConfigurationClass(configClass);
}
for (BeanMethod beanMethod : configClass.getBeanMethods()) {
loadBeanDefinitionsForBeanMethod(beanMethod);
}

loadBeanDefinitionsFromImportedResources(configClass.getImportedResources());
// 从configClass中获取ImportBeanDefinitionRegistrar
loadBeanDefinitionsFromRegistrars(configClass.getImportBeanDefinitionRegistrars());
}

回调其 registerBeanDefinitions 方法

1
2
3
4
private void loadBeanDefinitionsFromRegistrars(Map<ImportBeanDefinitionRegistrar, AnnotationMetadata> registrars) {
registrars.forEach((registrar, metadata) ->
registrar.registerBeanDefinitions(metadata, this.registry));
}

注册 BeanPostProcessor

注册 BeanPostProcessor 是由 spring 自己处理的(指的是 ApplicationContext 类型的容器)。

image-20200418012104632

ApplicationContext 进行 refresh 操作时,首先会对 BeanFactory 进行准备和一些处理工作,在这之后就会往 BeanFactory 中注册 BeanPostProcessor。它的主要思路是:

  1. BeanFactory 中获取 BeanPostProcessor 类型的 bean
  2. 调用 ConfigurableBeanFactoryaddBeanPostProcessor 方法往容器中注册 BeanPostProcessor

具体代码可参考 registerBeanPostProcessors