赞
踩
本文基于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;和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
表示字段的依赖注入点;
由上文可知,作为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
实现了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的创建请见下文分析。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。