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);

    

工作:

  1. 判断容器中是否包含了referenceAnnotationBeanPostProcessor名称的Bean,如果有,结束;
  2. 根据Bean的类型ReferenceAnnotationBeanPostProcessor.class,创建一个RootBeanDefinition实例;
  3. 设置Role属性;
  4. 注入容器中;
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
    工作:
  1. 创建结果集合List
  2. 获取beanClass所有的Method属性
  3. 获取所有修饰Method属性的注解,遍历
  4. getMergedAttributes判断Method是否被@Reference注解修饰,有则获取注解的所有信息;
  5. 找到set方法所对应的属性;
  6. 加入结果集合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;
    
    

工作:

  1. 先获取代表@Reference修饰的Field和Method信息类;在(一)步骤中,已经扫描完成,放入缓存,因此只需要先从缓存中获取;
  2. 执行属性注入;

InjectionMetadata#inject(Object target, String beanName, PropertyValues pvs)

作用: 执行属性注入
工作:

  1. 先获取被@Reference修饰的属性集合injectedElements;
  2. 遍历集合injectedElements
  3. 执行属性注入;
	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工作:

  1. 获取Field的类型;
  2. 获取对象getInjectedObject
  3. 设置为可访问
  4. 反射给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方法

获取注入属性实例;
工作:

  1. buildInjectedObjectCacheKey()生成注入对象的缓存key;
  2. 从缓存中获取 属性注入的实例;
  3. 如果存在, 直接返回;
  4. 如果不能存在, 生成属性注入的实例;
  5. 放入缓存中;
    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 : 待注入的属性类型;

工作:

  1. 获取该属性注入的服务Bean的名称referencedBeanName ;
  2. 获取referencedBeanName属性;
  3. buildReferenceBeanIfAbsent生成一个ReferenceBean 对象;
  4. registerReferenceBean 注入到Spring容器中, 这样就可以在其他地方就可以使用@Autowired注解自动注入;
  5. cacheInjectedReferenceBean-缓存bean实例;
  6. 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字符串;
工作:

  1. 创建一个ServiceBeanNameBuilder构建者对象, 传入@Reference注解信息, 注入的服务类型,环境信息;
  2. 生成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注解解析原理的主要内容,如果未能解决你的问题,请参考以下文章

Springboot整合Dubbo和Zookeeper

Dubbo源码学习整合Spring 容器实现服务优雅启动和停止

Duboo3.0+SpringBoot+zookeeper整合例子(附源码)

spring+spring mvc+mybatis+mysql+dubbo整合开发任务流程后台管理系统

深入浅出学习 DubboSpringBoot 与 Dubbo 整合

Dubbo学习-6-sprongboot整合dubbo