相关阅读
简介
本文基于Spring Boot 2.6.6
,dubbo-spring-boot-starter 3.0.6
环境。
本文主要分析Dubbo中注解DubboReference
的使用方式,并从源码分析其生效的实现原理;
使用
常用的使用方式有两种,下面分别介绍;
方式一
在自动注入的Bean上使用@DubboReference
,表示该Bean为Dubbo Reference,示例代码如下:
@RestController
public class DemoController {
// @Autowired可省略
@Autowired
@DubboReference
private DemoService demoService;
}
方式二
官方推荐在BeanMethod上使用@DubboReference
,这样可以一次定义,到处使用;
这种方式分两步:
- 定义
DubboReference
; - 注入
DubboReference
;
示例代码如下:
@Configuration
public class ReferenceConfig {
@Bean
@DubboReference
public ReferenceBean<DemoService> demoService() {
return new ReferenceBean<>();
}
}
@RestController
public class DemoController {
@Autowired
private DemoService demoService;
}
解析
注解DubboReference
的解析由ReferenceAnnotationBeanPostProcessor
完成;ReferenceAnnotationBeanPostProcessor
继承自AbstractAnnotationBeanPostProcessor
;
AbstractAnnotationBeanPostProcessor
实现了支持自定义注解标注待注入依赖的功能框架,类似于AutowiredAnnotationBeanPostProcessor
实现(支持@Autowired
标注待注入依赖);- 方式一,
ReferenceAnnotationBeanPostProcessor
会为标注了@DubboReference
的ReferenceBean
构建RootBeanDefinition
;方式二,ReferenceAnnotationBeanPostProcessor
会为标注了@DubboReference
的ReferenceBean
的RootBeanDefinition
填充Dubbo相关属性; - 由
ReferenceAnnotationBeanPostProcessor
(方式一)或者AutowiredAnnotationBeanPostProcessor
(方式二)实现ReferenceBean
的创建和注入; ReferenceBean
实现了InitializingBean
接口,故在实例化后会执行afterPropertiesSet
方法,此方法会借助ReferenceBeanManager
真正创建Dubbo Reference;
AbstractAnnotationBeanPostProcessor
和AutowiredAnnotationBeanPostProcessor
(Spring Boot源码简析 AutowiredAnnotationBeanPostProcessor)功能非常相似,AbstractAnnotationBeanPostProcessor
实现了支持自定义注解标注待注入依赖的功能框架,由子类指定自定义注解列表和查找注入依赖的细节;
接下来分析其核心方法实现;
构造方法
构造方法的参数列表表示自定义注解列表,代码如下:
public AbstractAnnotationBeanPostProcessor(Class<? extends Annotation>... annotationTypes) {
Assert.notEmpty(annotationTypes, "The argument of annotations' types must not empty");
// 指定支持的自定义注解列表
this.annotationTypes = annotationTypes;
}
注意:支持的自定义注解列表不支持修改,只能在子类的构造方法中调用父类的构造方法进行设置;
findInjectionMetadata
用于解析指定Class
中待注入的元数据,代码如下:
protected AnnotatedInjectionMetadata findInjectionMetadata(String beanName, Class<?> clazz, PropertyValues pvs) {
String cacheKey = (StringUtils.hasLength(beanName) ? beanName : clazz.getName());
// 此处实现了缓存,若已处理则可直接返回
AbstractAnnotationBeanPostProcessor.AnnotatedInjectionMetadata metadata = this.injectionMetadataCache.get(cacheKey);
if (needsRefreshInjectionMetadata(metadata, clazz)) {
synchronized (this.injectionMetadataCache) {
// DCL
metadata = this.injectionMetadataCache.get(cacheKey);
if (needsRefreshInjectionMetadata(metadata, clazz)) {
if (metadata != null) {
metadata.clear(pvs);
}
try {
// 解析待注入的元数据
metadata = buildAnnotatedMetadata(clazz);
// 缓存,以便下次直接使用
this.injectionMetadataCache.put(cacheKey, metadata);
} catch (NoClassDefFoundError err) {
throw new IllegalStateException("Failed to introspect object class [" + clazz.getName() +
"] for annotation metadata: could not find class that it depends on", err);
}
}
}
}
return metadata;
}
private boolean needsRefreshInjectionMetadata(AnnotatedInjectionMetadata metadata, Class<?> clazz) {
return (metadata == null || metadata.needsRefresh(clazz));
}
private AbstractAnnotationBeanPostProcessor.AnnotatedInjectionMetadata buildAnnotatedMetadata(final Class<?> beanClass) {
// 解析标注注解的字段
Collection<AbstractAnnotationBeanPostProcessor.AnnotatedFieldElement> fieldElements = findFieldAnnotationMetadata(beanClass);
// 解析标注注解的方法
Collection<AbstractAnnotationBeanPostProcessor.AnnotatedMethodElement> methodElements = findAnnotatedMethodMetadata(beanClass);
return new AnnotatedInjectionMetadata(beanClass, fieldElements, methodElements);
}
private List<AbstractAnnotationBeanPostProcessor.AnnotatedFieldElement> findFieldAnnotationMetadata(final Class<?> beanClass) {
final List<AbstractAnnotationBeanPostProcessor.AnnotatedFieldElement> elements = new LinkedList<AbstractAnnotationBeanPostProcessor.AnnotatedFieldElement>();
// 循环遍历beanClass及其父类声明的所有字段,直至其父类为空或者为Object
ReflectionUtils.doWithFields(beanClass, new ReflectionUtils.FieldCallback() {
@Override
public void doWith(Field field) throws IllegalArgumentException, IllegalAccessException {
// 遍历支持的注解列表
for (Class<? extends Annotation> annotationType : getAnnotationTypes()) {
// 获取字段上的注解信息
AnnotationAttributes attributes = getAnnotationAttributes(field, annotationType, getEnvironment(), true, true);
if (attributes != null) {
// 存在注解信息
if (Modifier.isStatic(field.getModifiers())) {
// 不支持静态字段
if (logger.isWarnEnabled()) {
logger.warn("@" + annotationType.getName() + " is not supported on static fields: " + field);
}
return;
}
// 保存该字段信息
elements.add(new AnnotatedFieldElement(field, attributes));
}
}
}
});
return elements;
}
private List<AbstractAnnotationBeanPostProcessor.AnnotatedMethodElement> findAnnotatedMethodMetadata(final Class<?> beanClass) {
final List<AbstractAnnotationBeanPostProcessor.AnnotatedMethodElement> elements = new LinkedList<AbstractAnnotationBeanPostProcessor.AnnotatedMethodElement>();
// 循环遍历beanClass及其父类声明的所有方法,直至其父类为空或者为Object
ReflectionUtils.doWithMethods(beanClass, new ReflectionUtils.MethodCallback() {
@Override
public void doWith(Method method) throws IllegalArgumentException, IllegalAccessException {
// 获取原始方法
Method bridgedMethod = findBridgedMethod(method);
if (!isVisibilityBridgeMethodPair(method, bridgedMethod)) {
// 过滤桥方法
return;
}
if (method.getAnnotation(Bean.class) != null) {
// 过滤BeanMethod
return;
}
// 遍历支持的注解列表
for (Class<? extends Annotation> annotationType : getAnnotationTypes()) {
// 获取方法上的注解信息
AnnotationAttributes attributes = getAnnotationAttributes(bridgedMethod, annotationType, getEnvironment(), true, true);
if (attributes != null && method.equals(ClassUtils.getMostSpecificMethod(method, beanClass))) {
if (Modifier.isStatic(method.getModifiers())) {
// 不支持静态字段
throw new IllegalStateException("When using @"+annotationType.getName() +" to inject interface proxy, it is not supported on static methods: "+method);
}
if (method.getParameterTypes().length != 1) {
// 方法参数校验失败
throw new IllegalStateException("When using @"+annotationType.getName() +" to inject interface proxy, the method must have only one parameter: "+method);
}
PropertyDescriptor pd = BeanUtils.findPropertyForMethod(bridgedMethod, beanClass);
// 保存该方法信息
elements.add(new AnnotatedMethodElement(method, pd, attributes));
}
}
}
});
return elements;
}
postProcessMergedBeanDefinition
此方法中会解析出Class
的待注入的元数据,并支持子类做进一步处理,代码如下:
public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) {
if (beanType != null) {
// 解析待注入的元数据
AnnotatedInjectionMetadata metadata = findInjectionMetadata(beanName, beanType, null);
// 注册外部管理的配置方法或者字段
metadata.checkConfigMembers(beanDefinition);
try {
// 留给子类做进一步处理
prepareInjection(metadata);
} catch (Exception e) {
logger.error("Prepare injection of @"+getAnnotationType().getSimpleName()+" failed", e);
}
}
}
postProcessPropertyValues
此方法中会查找Class
的待注入的元数据(postProcessMergedBeanDefinition
方法已解析并缓存,此处可直接获取缓存结果),并支持子类做进一步处理,然后就注入依赖,代码如下:
public PropertyValues postProcessPropertyValues(
PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeansException {
try {
// 查找待注入的元数据
AnnotatedInjectionMetadata metadata = findInjectionMetadata(beanName, bean.getClass(), pvs);
// 留给子类做进一步处理
prepareInjection(metadata);
// 注入依赖
metadata.inject(bean, beanName, pvs);
} catch (BeansException ex) {
throw ex;
} catch (Throwable ex) {
throw new BeanCreationException(beanName, "Injection of @" + getAnnotationType().getSimpleName()
+ " dependencies is failed", ex);
}
return pvs;
}
// InjectionMetadata.java
public void inject(Object target, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
Collection<InjectedElement> checkedElements = this.checkedElements;
Collection<InjectedElement> elementsToIterate =
(checkedElements != null ? checkedElements : this.injectedElements);
if (!elementsToIterate.isEmpty()) {
// 遍历待注入点
for (InjectedElement element : elementsToIterate) {
// 注入依赖
element.inject(target, beanName, pvs);
}
}
}
AbstractAnnotationBeanPostProcessor
使用内部类自定义实现了InjectionMetadata
和InjectionMetadata.InjectedElement
,具体如下:
protected static class AnnotatedInjectionMetadata extends InjectionMetadata
protected class AnnotatedInjectElement extends InjectionMetadata.InjectedElement
protected class AnnotatedMethodElement extends AnnotatedInjectElement
public class AnnotatedFieldElement extends AnnotatedInjectElement
AnnotatedInjectionMetadata
内部使用两个Collection
保存AnnotatedMethodElement
、AnnotatedFieldElement
;
AnnotatedInjectElement
重写了inject
方法,代码如下:
protected void inject(Object bean, String beanName, PropertyValues pvs) throws Throwable {
// 从容器中找到依赖
Object injectedObject = getInjectedObject(attributes, bean, beanName, getInjectedType(), this);
// 注入依赖,区分字段、方法
if (member instanceof Field) {
Field field = (Field) member;
ReflectionUtils.makeAccessible(field);
field.set(bean, injectedObject);
} else if (member instanceof Method) {
Method method = (Method) member;
ReflectionUtils.makeAccessible(method);
method.invoke(bean, injectedObject);
}
}
// AbstractAnnotationBeanPostProcessor.java
protected Object getInjectedObject(AnnotationAttributes attributes, Object bean, String beanName, Class<?> injectedType,
AnnotatedInjectElement injectedElement) throws Exception {
// 查找依赖的算法细节由子类实现
return doGetInjectedBean(attributes, bean, beanName, injectedType, injectedElement);
}
AnnotatedMethodElement
表示方法的依赖注入点;
AnnotatedFieldElement
表示字段的依赖注入点;
ReferenceAnnotationBeanPostProcessor
由上文可知,作为AbstractAnnotationBeanPostProcessor
的子类,ReferenceAnnotationBeanPostProcessor
必须指定自定义注解列表和查找注入依赖的细节;
自定义注解列表
自定义注解列表是在构造方法中指定的,代码如下:
public ReferenceAnnotationBeanPostProcessor() {
super(DubboReference.class, Reference.class, com.alibaba.dubbo.config.annotation.Reference.class);
}
查找注入依赖
根据beanName在Spring容器中查找依赖,需要确保依赖已经提前初始化完成,代码如下:
protected Object doGetInjectedBean(AnnotationAttributes attributes, Object bean, String beanName, Class<?> injectedType,
AnnotatedInjectElement injectedElement) throws Exception {
if (injectedElement.injectedObject == null) {
throw new IllegalStateException("The AnnotatedInjectElement of @DubboReference should be inited before injection");
}
// 根据beanName在Spring容器中查找依赖
return getBeanFactory().getBean((String) injectedElement.injectedObject);
}
下面分析ReferenceAnnotationBeanPostProcessor
如何解析处理不同使用方式下的@DubboReference
标注的Bean的BeanDefinition
;
方式一
ReferenceAnnotationBeanPostProcessor
实现了BeanFactoryPostProcessor
接口,故在AbstractApplicationContext.invokeBeanFactoryPostProcessors
方法中会执行其postProcessBeanFactory
方法,其实现中相关核心代码如下:
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
String[] beanNames = beanFactory.getBeanDefinitionNames();
// 遍历Spring容器中所有的BeanDefinition
for (String beanName : beanNames) {
Class<?> beanType;
if (beanFactory.isFactoryBean(beanName)){
BeanDefinition beanDefinition = beanFactory.getBeanDefinition(beanName);
if (isReferenceBean(beanDefinition)) {
continue;
}
if (isAnnotatedReferenceBean(beanDefinition)) {
// 方式二的处理
processReferenceAnnotatedBeanDefinition(beanName, (AnnotatedBeanDefinition) beanDefinition);
continue;
}
String beanClassName = beanDefinition.getBeanClassName();
beanType = ClassUtils.resolveClass(beanClassName, getClassLoader());
} else {
beanType = beanFactory.getType(beanName);
}
if (beanType != null) {
// 查找待注入的元数据
// 方式一的处理
AnnotatedInjectionMetadata metadata = findInjectionMetadata(beanName, beanType, null);
try {
// 进一步处理,构建并注册DubboReference标注的Bean的BeanDefinition
prepareInjection(metadata);
} catch (BeansException e) {
throw e;
} catch (Exception e) {
throw new IllegalStateException("Prepare dubbo reference injection element failed", e);
}
}
}
...
}
方式一中,标注了@DubboReference
的Bean并没有BeanDefinition
,所以需要在依赖注入前注册该Bean的BeanDefinition
,此动作在prepareInjection
方法中实现,代码如下:
protected void prepareInjection(AnnotatedInjectionMetadata metadata) throws BeansException {
try {
// 遍历字段注入点
for (AnnotatedFieldElement fieldElement : metadata.getFieldElements()) {
if (fieldElement.injectedObject != null) {
// 已经处理过则可以跳过
continue;
}
Class<?> injectedType = fieldElement.field.getType();
AnnotationAttributes attributes = fieldElement.attributes;
// 注册BeanDefinition
String referenceBeanName = registerReferenceBean(fieldElement.getPropertyName(), injectedType, attributes, fieldElement.field);
// 缓存该beanName,防止重复注册
fieldElement.injectedObject = referenceBeanName;
injectedFieldReferenceBeanCache.put(fieldElement, referenceBeanName);
}
// 遍历方法注入点
for (AnnotatedMethodElement methodElement : metadata.getMethodElements()) {
if (methodElement.injectedObject != null) {
// 已经处理过则可以跳过
continue;
}
Class<?> injectedType = methodElement.getInjectedType();
AnnotationAttributes attributes = methodElement.attributes;
// 注册BeanDefinition
String referenceBeanName = registerReferenceBean(methodElement.getPropertyName(), injectedType, attributes, methodElement.method);
// 缓存该beanName,防止重复注册
methodElement.injectedObject = referenceBeanName;
injectedMethodReferenceBeanCache.put(methodElement, referenceBeanName);
}
} catch (ClassNotFoundException e) {
throw new BeanCreationException("prepare reference annotation failed", e);
}
}
registerReferenceBean
方法中构建了标注了@DubboReference
的Bean的BeanDefinition
后,再注册到Spring容器中,有了BeanDefinition
,那么后续就方便创建实例了;
Bean的声明信息如下:
@Autowired
@DubboReference
private DemoService demoService;
那么该Bean是由ReferenceAnnotationBeanPostProcessor
还是AutowiredAnnotationBeanPostProcessor
完成依赖注入呢,还是说二者都会完成注入?
在postProcessMergedBeanDefinition
方法中,二者都会执行metadata.checkConfigMembers(beanDefinition);
,该方法代码如下:
public void checkConfigMembers(RootBeanDefinition beanDefinition) {
Set<InjectedElement> checkedElements = new LinkedHashSet<>(this.injectedElements.size());
for (InjectedElement element : this.injectedElements) {
Member member = element.getMember();
if (!beanDefinition.isExternallyManagedConfigMember(member)) {
beanDefinition.registerExternallyManagedConfigMember(member);
checkedElements.add(element);
}
}
this.checkedElements = checkedElements;
}
二者各自维护了injectionMetadataCache
,beanDefinition
是同一个,metadata
是各自持有的,那么谁先执行,那么谁的checkedElements
就是有值的;
在inject
方法中,优先根据checkedElements
进行处理,所以可知后执行的MergedBeanDefinitionPostProcessor
因为checkedElements
为空集合而不会完成注入的动作;那么问题就变成:ReferenceAnnotationBeanPostProcessor
和AutowiredAnnotationBeanPostProcessor
,谁的postProcessMergedBeanDefinition
方法先执行?
在AbstractAutowireCapableBeanFactory.applyMergedBeanDefinitionPostProcessors
方法中,会遍历执行Spring容器中所有的MergedBeanDefinitionPostProcessor
,代码如下:
protected void applyMergedBeanDefinitionPostProcessors(RootBeanDefinition mbd, Class<?> beanType, String beanName) {
for (MergedBeanDefinitionPostProcessor processor : getBeanPostProcessorCache().mergedDefinition) {
processor.postProcessMergedBeanDefinition(mbd, beanType, beanName);
}
}
mergedDefinition
中的顺序来自于Spring容器中BeanPostProcessor
的添加顺序,到此,问题就变成:ReferenceAnnotationBeanPostProcessor
和AutowiredAnnotationBeanPostProcessor
谁先添加到Spring容器?
ReferenceAnnotationBeanPostProcessor
是在DubboInfraBeanRegisterPostProcessor.postProcessBeanFactory
方法中添加到Spring容器的,由AbstractApplicationContext.invokeBeanFactoryPostProcessors
调用;AutowiredAnnotationBeanPostProcessor
是在AbstractApplicationContext.registerBeanPostProcessors
方法中添加到Spring容器的;
至此,可以看出ReferenceAnnotationBeanPostProcessor
早于AutowiredAnnotationBeanPostProcessor
添加到容器中,故由ReferenceAnnotationBeanPostProcessor
完成依赖注入;
依赖注入的动作发生在ReferenceAnnotationBeanPostProcessor.postProcessPropertyValues
方法中,代码如下:
public PropertyValues postProcessPropertyValues(
PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeansException {
try {
AnnotatedInjectionMetadata metadata = findInjectionMetadata(beanName, bean.getClass(), pvs);
// 确保注入前,Reference BeanDefinition已存在
prepareInjection(metadata);
// 注入Reference
metadata.inject(bean, beanName, pvs);
} catch (BeansException ex) {
throw ex;
} catch (Throwable ex) {
throw new BeanCreationException(beanName, "Injection of @" + getAnnotationType().getSimpleName()
+ " dependencies is failed", ex);
}
return pvs;
}
方式二
同方式一,也是在ReferenceAnnotationBeanPostProcessor.postProcessBeanFactory
方法中处理,相关核心代码如下:
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
String[] beanNames = beanFactory.getBeanDefinitionNames();
// 遍历Spring容器中所有的BeanDefinition
for (String beanName : beanNames) {
Class<?> beanType;
if (beanFactory.isFactoryBean(beanName)){
// DubboReference由BeanMethod定义,故是FactoryBean
BeanDefinition beanDefinition = beanFactory.getBeanDefinition(beanName);
if (isReferenceBean(beanDefinition)) {
continue;
}
// BeanMethod的返回值为ReferenceBean
if (isAnnotatedReferenceBean(beanDefinition)) {
// 方式二的处理
processReferenceAnnotatedBeanDefinition(beanName, (AnnotatedBeanDefinition) beanDefinition);
// 处理完直接进行下一循环
continue;
}
String beanClassName = beanDefinition.getBeanClassName();
beanType = ClassUtils.resolveClass(beanClassName, getClassLoader());
} else {
beanType = beanFactory.getType(beanName);
}
if (beanType != null) {
// 查找待注入的元数据
// 方式一的处理
AnnotatedInjectionMetadata metadata = findInjectionMetadata(beanName, beanType, null);
try {
// 进一步处理,构建并注册DubboReference标注的Bean的BeanDefinition
prepareInjection(metadata);
} catch (BeansException e) {
throw e;
} catch (Exception e) {
throw new IllegalStateException("Prepare dubbo reference injection element failed", e);
}
}
}
...
}
方式二中,Spring容器中已经存在标注了@DubboReference
的Bean的BeanDefinition
,所以processReferenceAnnotatedBeanDefinition
方法只是对其BeanDefinition
的属性做进一步处理;此时DubboReference
相当于普通的Bean,由AutowiredAnnotationBeanPostProcessor
完成依赖注入动作;
ReferenceBean
ReferenceBean
实现了InitializingBean
接口,故实例化后,会执行其afterPropertiesSet
方法,代码如下:
public void afterPropertiesSet() throws Exception {
ConfigurableListableBeanFactory beanFactory = getBeanFactory();
Assert.notEmptyString(getId(), "The id of ReferenceBean cannot be empty");
BeanDefinition beanDefinition = beanFactory.getBeanDefinition(getId());
this.interfaceClass = (Class<?>) beanDefinition.getAttribute(ReferenceAttributes.INTERFACE_CLASS);
this.interfaceName = (String) beanDefinition.getAttribute(ReferenceAttributes.INTERFACE_NAME);
Assert.notNull(this.interfaceClass, "The interface class of ReferenceBean is not initialized");
// 获取referenceProps
if (beanDefinition.hasAttribute(Constants.REFERENCE_PROPS)) {
referenceProps = (Map<String, Object>) beanDefinition.getAttribute(Constants.REFERENCE_PROPS);
} else {
if (beanDefinition instanceof AnnotatedBeanDefinition) {
if (referenceProps == null) {
referenceProps = new LinkedHashMap<>();
}
ReferenceBeanSupport.convertReferenceProps(referenceProps, interfaceClass);
if (this.interfaceName == null) {
this.interfaceName = (String) referenceProps.get(ReferenceAttributes.INTERFACE);
}
} else {
propertyValues = beanDefinition.getPropertyValues();
}
}
Assert.notNull(this.interfaceName, "The interface name of ReferenceBean is not initialized");
ReferenceBeanManager referenceBeanManager = beanFactory.getBean(ReferenceBeanManager.BEAN_NAME, ReferenceBeanManager.class);
// 借助ReferenceBeanManager完成Dubbo Reference真正创建
referenceBeanManager.addReference(this);
}
至此,@DubboReference
的源码分析就结束啦,Dubbo Reference的创建请见下文分析。