Dubbo学习记录 -- Spring整合Dubbo中@Reference注解解析原理
Posted ~玄霄-
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Dubbo学习记录 -- Spring整合Dubbo中@Reference注解解析原理相关的知识,希望对你有一定的参考价值。
Spring整合Dubbo中@Reference注解解析原理
@Reference: 可以用在属性或者方法, 意味着需要引用某个Dubbo服务, 那么Dubbo整合Spring后, 我很好奇怎么把这个过程完成的。
package org.apache.dubbo.demo.provider;
public class 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")
@PropertySource("classpath:/spring/dubbo-provider.properties")
static class ProviderConfiguration
//@EnabeDubbo注解
@EnableDubboConfig
@DubboComponentScan
public @interface EnableDubbo
//该属性的值也是DubboComponentScan属性basePackages的值;
@AliasFor(annotation = DubboComponentScan.class, attribute = "basePackages")
String[] scanBasePackages() default ;
@AliasFor(annotation = DubboComponentScan.class, attribute = "basePackageClasses")
Class<?>[] scanBasePackageClasses() default ;
@AliasFor(annotation = EnableDubboConfig.class, attribute = "multiple")
boolean multipleConfig() default true;
- @DubboComponentScan: 用来扫描@Service 和@Reference注解修饰的类;
DubboComponentScanRegistrar
public class DubboComponentScanRegistrar implements ImportBeanDefinitionRegistrar
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry)
System.out.println("执行DubboComponentScanRegistrar");
// 拿到DubboComponentScan注解所定义的包路径,扫描该package下的类,识别这些类上
Set<String> packagesToScan = getPackagesToScan(importingClassMetadata);
// 注册ServiceAnnotationBeanPostProcessor一个Bean
// 实现了BeanDefinitionRegistryPostProcessor接口,所以在Spring启动时会调用postProcessBeanDefinitionRegistry方法
// 该方法会进行扫描,扫描@Service注解了的类,然后生成BeanDefinition(会生成两个,一个普通的bean,一个ServiceBean),后续的Spring周期中会生成Bean
// 在ServiceBean中会监听ContextRefreshedEvent事件,一旦Spring启动完后,就会进行服务导出
registerServiceAnnotationBeanPostProcessor(packagesToScan, registry);
// 注册ReferenceAnnotationBeanPostProcessor
// 实现了AnnotationInjectedBeanPostProcessor接口,继而实现了InstantiationAwareBeanPostProcessorAdapter接口
// 所以Spring在启动时,在对属性进行注入时会调用AnnotationInjectedBeanPostProcessor接口中的postProcessPropertyValues方法
// 在这个过程中会按照@Refrence注解的信息去生成一个RefrenceBean对象
registerReferenceAnnotationBeanPostProcessor(registry);
- registerServiceAnnotationBeanPostProcessor方法用来解析@Service注解修饰的类, 最后会获得一个服务实现类, 一个ServiceBean类注入容器;
- registerReferenceAnnotationBeanPostProcessor: 是用来解析@Reference注解的方法;
registerReferenceAnnotationBeanPostProcessor(registry)
/**
* Registers @link ReferenceAnnotationBeanPostProcessor into @link BeanFactory
*
* @param registry @link BeanDefinitionRegistry
*/
private void registerReferenceAnnotationBeanPostProcessor(BeanDefinitionRegistry registry)
// Register @Reference Annotation Bean Processor
// 注册一个ReferenceAnnotationBeanPostProcessor做为bean,ReferenceAnnotationBeanPostProcessor是一个BeanPostProcessor
BeanRegistrar.registerInfrastructureBean(registry,
ReferenceAnnotationBeanPostProcessor.BEAN_NAME, ReferenceAnnotationBeanPostProcessor.class);
工作:
- 判断容器中是否包含了referenceAnnotationBeanPostProcessor名称的Bean,如果有,结束;
- 根据Bean的类型ReferenceAnnotationBeanPostProcessor.class,创建一个RootBeanDefinition实例;
- 设置Role属性;
- 注入容器中;
public class BeanRegistrar
/**
* Register Infrastructure Bean
*
* @param beanDefinitionRegistry @link BeanDefinitionRegistry
* @param beanType the type of bean
* @param beanName the name of bean
*/
public static void registerInfrastructureBean(BeanDefinitionRegistry beanDefinitionRegistry,
String beanName,
Class<?> beanType)
if (!beanDefinitionRegistry.containsBeanDefinition(beanName))
RootBeanDefinition beanDefinition = new RootBeanDefinition(beanType);
beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
beanDefinitionRegistry.registerBeanDefinition(beanName, beanDefinition);
ReferenceAnnotationBeanPostProcessor
- 继承了AnnotationInjectedBeanPostProcessor类,该类又继承了MergedBeanDefinitionPostProcessor,InstantiationAwareBeanPostProcessorAdapter 类;
- 应用启动的时候, 对于我们引入服务的类, Spring会进行对这些类进行依赖注入(类似@Autowired)
- 依赖注入的时候会调用AnnotationInjectedBeanPostProcessor#postProcessPropertyValues()方法,这个方法里面使用了子类的处理逻辑,按照子类的处理逻辑进行依赖注入;
- 在依赖注入前,会先执行MergedBeanDefinitionPostProcessor#postProcessMergedBeanDefinition方法, 子类AnnotationInjectedBeanPostProcessor实现了这个接口, 目的是扫描所有被@Reference注解修饰的方法和属性的准备工作;
public class ReferenceAnnotationBeanPostProcessor extends AnnotationInjectedBeanPostProcessor implements
ApplicationContextAware, ApplicationListener
//...
public abstract class AnnotationInjectedBeanPostProcessor extends
InstantiationAwareBeanPostProcessorAdapter implements MergedBeanDefinitionPostProcessor, PriorityOrdered,
BeanFactoryAware, BeanClassLoaderAware, EnvironmentAware, DisposableBean
//...
public abstract class InstantiationAwareBeanPostProcessorAdapter implements SmartInstantiationAwareBeanPostProcessor
//....
@Override
public PropertyValues postProcessPropertyValues(
PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeansException
return pvs;
MergedBeanDefinitionPostProcessor#postProcessMergedBeanDefinition方法
由子类AnnotationInjectedBeanPostProcessor 实现了这个方法;
public interface MergedBeanDefinitionPostProcessor extends BeanPostProcessor
void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName);
public abstract class AnnotationInjectedBeanPostProcessor extends
InstantiationAwareBeanPostProcessorAdapter implements MergedBeanDefinitionPostProcessor, PriorityOrdered,
BeanFactoryAware, BeanClassLoaderAware, EnvironmentAware, DisposableBean
//...
@Override
public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName)
if (beanType != null)
InjectionMetadata metadata = findInjectionMetadata(beanName, beanType, null);
metadata.checkConfigMembers(beanDefinition);
一、findInjectionMetadata(beanName, beanType, null)
private InjectionMetadata findInjectionMetadata(String beanName, Class<?> clazz, PropertyValues pvs)
// Fall back to class name as cache key, for backwards compatibility with custom callers.
String cacheKey = (StringUtils.hasLength(beanName) ? beanName : clazz.getName());
// Quick check on the concurrent map first, with minimal locking.
AnnotationInjectedBeanPostProcessor.AnnotatedInjectionMetadata metadata = this.injectionMetadataCache.get(cacheKey);
if (InjectionMetadata.needsRefresh(metadata, clazz))
synchronized (this.injectionMetadataCache)
metadata = this.injectionMetadataCache.get(cacheKey);
if (InjectionMetadata.needsRefresh(metadata, clazz))
if (metadata != null)
metadata.clear(pvs);
try
metadata = buildAnnotatedMetadata(clazz);
this.injectionMetadataCache.put(cacheKey, metadata);
catch (NoClassDefFoundError err)
//...
return metadata;
- 这些元数据是通过反射获取的,由于反射本身性能不高,所以拿到一些元数据后,需要放入本地缓存injectionMetadataCache中,下次直接从缓存中获取;
- 扫描 @Reference修饰的属性或者方法,对应类型为AnnotatedFieldElement, AnnotatedMethodElement
- injectionMetadataCache缓存 的 key为 bean的名称,或者类的名称, 值的类型AnnotatedInjectionMetadata;
- AnnotatedInjectionMetadata里面包装两个集合, 被@reference修饰的属性集合, 被@Reference修饰的方法集合
buildAnnotatedMetadata(clazz)
工作:
- 获取哪些Filed上有@Reference注解
- 获取哪些方法上有@Reference注解
- 创建一个AnnotatedInjectionMetadata实例, 参数是属性和方法集合, 属性注入会按照这个类去进行的;返回实例;
private AnnotationInjectedBeanPostProcessor.AnnotatedInjectionMetadata buildAnnotatedMetadata(final Class<?> beanClass)
// 扫描Field
Collection<AnnotationInjectedBeanPostProcessor.AnnotatedFieldElement> fieldElements = findFieldAnnotationMetadata(beanClass);
// 扫描Method
Collection<AnnotationInjectedBeanPostProcessor.AnnotatedMethodElement> methodElements = findAnnotatedMethodMetadata(beanClass);
// 返回的是Dubbo定义的AnnotatedInjectionMetadata,接下来就会使用这个类去进行属性注入
return new AnnotationInjectedBeanPostProcessor.AnnotatedInjectionMetadata(beanClass, fieldElements, methodElements);
-
扫描Field
工作: -
创建结果集合List;
-
遍历beanClass的所有的Field;
-
获取Feild上所有的注解;
-
getMergedAttributes获取@Reference注解, 如果不存在,返回空;
-
存在@Reference注解,就会获取@reference注解的所有属性,AnnotationAttributes 存储就是注解的属性信息;
-
存在Reference注解,就加入集合List;
private List<AnnotationInjectedBeanPostProcessor.AnnotatedFieldElement> findFieldAnnotationMetadata(final Class<?> beanClass)
final List<AnnotationInjectedBeanPostProcessor.AnnotatedFieldElement> elements = new LinkedList<AnnotationInjectedBeanPostProcessor.AnnotatedFieldElement>();
ReflectionUtils.doWithFields(beanClass, field ->
for (Class<? extends Annotation> annotationType : getAnnotationTypes())
AnnotationAttributes attributes = getMergedAttributes(field, annotationType, getEnvironment(), true);
if (attributes != null)
//...
elements.add(new AnnotatedFieldElement(field, attributes));
);
return elements;
- 扫描Method
工作:
- 创建结果集合List
- 获取beanClass所有的Method属性
- 获取所有修饰Method属性的注解,遍历
- getMergedAttributes判断Method是否被@Reference注解修饰,有则获取注解的所有信息;
- 找到set方法所对应的属性;
- 加入结果集合List
private List<AnnotationInjectedBeanPostProcessor.AnnotatedMethodElement> findAnnotatedMethodMetadata(final Class<?> beanClass)
final List<AnnotationInjectedBeanPostProcessor.AnnotatedMethodElement> elements = new LinkedList<AnnotationInjectedBeanPostProcessor.AnnotatedMethodElement>();
ReflectionUtils.doWithMethods(beanClass, method ->
Method bridgedMethod = findBridgedMethod(method);
for (Class<? extends Annotation> annotationType : getAnnotationTypes())
AnnotationAttributes attributes = getMergedAttributes(bridgedMethod, annotationType, getEnvironment(), true);
if (attributes != null && method.equals(ClassUtils.getMostSpecificMethod(method, beanClass)))
//....
// 找到set方法所对应的属性
PropertyDescriptor pd = BeanUtils.findPropertyForMethod(bridgedMethod, beanClass);
elements.add(new AnnotatedMethodElement(method, pd, attributes));
);
return elements;
获取完之后, 退出, 返回AnnotatedInjectionMetadata到(一)步骤中的调用处,然后会将这些Field和Method信息放入缓存;
postProcessPropertyValues
InstantiationAwareBeanPostProcessorAdapter抽象类已经定义好了该方法,子类AnnotationInjectedBeanPostProcessor 重写该方法,进行@Reference的依赖注入过程;
public abstract class InstantiationAwareBeanPostProcessorAdapter implements SmartInstantiationAwareBeanPostProcessor
@Override
public PropertyValues postProcessPropertyValues(
PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeansException
return pvs;
public abstract class AnnotationInjectedBeanPostProcessor extends
InstantiationAwareBeanPostProcessorAdapter implements MergedBeanDefinitionPostProcessor, PriorityOrdered,
BeanFactoryAware, BeanClassLoaderAware, EnvironmentAware, DisposableBean
@Override
public PropertyValues postProcessPropertyValues(
PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeanCreationException
// 寻找需要注入的属性(被@Reference标注的Field)
InjectionMetadata metadata = findInjectionMetadata(beanName, bean.getClass(), pvs);
try
metadata.inject(bean, beanName, pvs);
catch(Exception e)
//..异常处理
return pvs;
工作:
- 先获取代表@Reference修饰的Field和Method信息类;在(一)步骤中,已经扫描完成,放入缓存,因此只需要先从缓存中获取;
- 执行属性注入;
InjectionMetadata#inject(Object target, String beanName, PropertyValues pvs)
作用: 执行属性注入
工作:
- 先获取被@Reference修饰的属性集合injectedElements;
- 遍历集合injectedElements
- 执行属性注入;
public void inject(Object target, String beanName, PropertyValues pvs) throws Throwable
Collection<InjectedElement> elementsToIterate =
(this.checkedElements != null ? this.checkedElements : this.injectedElements);
if (!elementsToIterate.isEmpty())
boolean debug = logger.isDebugEnabled();
for (InjectedElement element : elementsToIterate)
if (debug)
logger.debug("Processing injected element of bean '" + beanName + "': " + element);
element.inject(target, beanName, pvs);
AnnotatedFieldElement#inject(target, beanName, pvs)
- InjectedElement 是 InjectionMetadata内部类,定义了inject方法, 但是代表被@Reference修饰的属性的类是AnnotatedFieldElement
- 该类继承了InjectedElement ,重写了inject方法, 因此调用InjectedElement 其实就是调用AnnotatedFieldElement的inject方法
public class AnnotatedFieldElement extends InjectionMetadata.InjectedElement
inject工作:
- 获取Field的类型;
- 获取对象getInjectedObject
- 设置为可访问
- 反射给Field设值;
@Override
protected void inject(Object bean, String beanName, PropertyValues pvs) throws Throwable
// 给bean对象进行属性赋值
Class<?> injectedType = field.getType();
// 获取对象,然后进行注入
Object injectedObject = getInjectedObject(attributes, bean, beanName, injectedType, this);
ReflectionUtils.makeAccessible(field);
// 字段赋值,injectedObject就是值
field.set(bean, injectedObject);
AnnotationInjectedBeanPostProcessor#getInjectedObject方法
获取注入属性实例;
工作:
- buildInjectedObjectCacheKey()生成注入对象的缓存key;
- 从缓存中获取 属性注入的实例;
- 如果存在, 直接返回;
- 如果不能存在, 生成属性注入的实例;
- 放入缓存中;
protected Object getInjectedObject(AnnotationAttributes attributes, Object bean, String beanName, Class<?> injectedType,
InjectionMetadata.InjectedElement injectedElement) throws Exception
// ServiceBean:org.apache.dubbo.demo.DemoService#source=private org.apache.dubbo.demo.DemoService org.apache.dubbo.demo.consumer.comp.DemoServiceComponent.demoService#attributes=parameters=[Ljava.lang.String;@42e25b0b
// 哪个Service应用了哪个类型的服务,通过什么方式引入的
String cacheKey = buildInjectedObjectCacheKey(attributes, bean, beanName, injectedType, injectedElement);
// cacheKey很鸡肋,属性名不一样的时候,cacheKey不一样,导致不能缓存, 在一个Service中@Reference两次同一个服务缓存不到
Object injectedObject = injectedObjectsCache.get(cacheKey);
if (injectedObject == null)
// 生成Bean
injectedObject = doGetInjectedBean(attributes, bean, beanName, injectedType, injectedElement);
// Customized inject-object if necessary
injectedObjectsCache.putIfAbsent(cacheKey, injectedObject);
return injectedObject;
ReferenceAnnotationBeanPostProcessor#doGetInjectedBean
参数:
- attributes: 代表@Reference注解的所有配置的属性信息;
- bean : 代表执行属性注入的类Bean实例;
- beanName: 代表执行属性注入的类Bean实例的名称;
- injectedType : 待注入的属性类型;
工作:
- 获取该属性注入的服务Bean的名称referencedBeanName ;
- 获取referencedBeanName属性;
- buildReferenceBeanIfAbsent生成一个ReferenceBean 对象;
- registerReferenceBean 注入到Spring容器中, 这样就可以在其他地方就可以使用@Autowired注解自动注入;
- cacheInjectedReferenceBean-缓存bean实例;
- getOrCreateProxy - 创建一个代理对象返回;也就是意味着,最后注入的属性是一个代理对象;
@Override
protected Object doGetInjectedBean(AnnotationAttributes attributes, Object bean, String beanName, Class<?> injectedType,
InjectionMetadata.InjectedElement injectedElement) throws Exception
//该属性注入的服务Bean的名称referencedBeanName
String referencedBeanName = buildReferencedBeanName(attributes, injectedType);
/**
* The name of bean that is declared by @link Reference @Reference annotation injection
*/
// @Reference(methods=[Lorg.apache.dubbo.config.annotation.Method;@39b43d60) org.apache.dubbo.demo.DemoService
// 我要生成一个RefrenceBean,对应的beanName, 根据@Reference注解来标识不同
String referenceBeanName = getReferenceBeanName(attributes, injectedType);
// 生成一个ReferenceBean对象
ReferenceBean referenceBean = buildReferenceBeanIfAbsent(referenceBeanName, attributes, injectedType);
// 把referenceBean添加到Spring容器中去
registerReferenceBean(referencedBeanName, referenceBean, attributes, injectedType);
//缓存
cacheInjectedReferenceBean(referenceBean, injectedElement);
// 创建一个代理对象,Service中的属性被注入的就是这个代理对象
// 内部会调用referenceBean.get();
return getOrCreateProxy(referencedBeanName, referenceBeanName, referenceBean, injectedType);
ReferenceAnnotationBeanPostProcessor#buildReferencedBeanName
创建一个ReferencedBeanName字符串;
工作:
- 创建一个ServiceBeanNameBuilder构建者对象, 传入@Reference注解信息, 注入的服务类型,环境信息;
- 生成ReferencedBeanName字符串;
- 该名称是以 注入服务接口类名 + 版本号 + 分组名称 格式生成的;
- 如: ServiceBean:org.apache.dubbo.demo.DemoService 表示得到该服务Bean的beanName
private String buildReferencedBeanName(AnnotationAttributes attributes, Class<?> serviceInterfaceType)
ServiceBeanNameBuilder serviceBeanNameBuilder = create(attributes, serviceInterfaceType, getEnvironment());
return serviceBeanNameBuilder.build();
// ServiceBeanNameBuilder # builder()
public String build()
StringBuilder beanNameBuilder = new StringBuilder("ServiceBean");
// Required
append(b以上是关于Dubbo学习记录 -- Spring整合Dubbo中@Reference注解解析原理的主要内容,如果未能解决你的问题,请参考以下文章
Dubbo源码学习整合Spring 容器实现服务优雅启动和停止
Duboo3.0+SpringBoot+zookeeper整合例子(附源码)
spring+spring mvc+mybatis+mysql+dubbo整合开发任务流程后台管理系统