0


Dubbo学习记录(八) -- Spring整合Dubbo中@Reference注解解析原理

Spring整合Dubbo中@Reference注解解析原理

@Reference: 可以用在属性或者方法, 意味着需要引用某个Dubbo服务, 那么Dubbo整合Spring后, 我很好奇怎么把这个过程完成的。

package org.apache.dubbo.demo.provider;publicclassApplication{publicstaticvoidmain(String[] args)throws Exception {
        AnnotationConfigApplicationContext context =newAnnotationConfigApplicationContext(ProviderConfiguration.class);
        context.start();

        System.in.read();}@Configuration@EnableDubbo(scanBasePackages ="org.apache.dubbo.demo.provider")@PropertySource("classpath:/spring/dubbo-provider.properties")staticclassProviderConfiguration{}}//@EnabeDubbo注解@EnableDubboConfig@DubboComponentScanpublic @interfaceEnableDubbo{//该属性的值也是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")booleanmultipleConfig()defaulttrue;}
  • @DubboComponentScan: 用来扫描@Service 和@Reference注解修饰的类;

DubboComponentScanRegistrar

publicclassDubboComponentScanRegistrarimplementsImportBeanDefinitionRegistrar{@OverridepublicvoidregisterBeanDefinitions(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}
     */privatevoidregisterReferenceAnnotationBeanPostProcessor(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. 注入容器中;
publicclassBeanRegistrar{/**
     * Register Infrastructure Bean
     *
     * @param beanDefinitionRegistry {@link BeanDefinitionRegistry}
     * @param beanType               the type of bean
     * @param beanName               the name of bean
     */publicstaticvoidregisterInfrastructureBean(BeanDefinitionRegistry beanDefinitionRegistry,
                                                  String beanName,
                                                  Class<?> beanType){if(!beanDefinitionRegistry.containsBeanDefinition(beanName)){
            RootBeanDefinition beanDefinition =newRootBeanDefinition(beanType);
            beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
            beanDefinitionRegistry.registerBeanDefinition(beanName, beanDefinition);}}}

ReferenceAnnotationBeanPostProcessor

  • 继承了AnnotationInjectedBeanPostProcessor类,该类又继承了MergedBeanDefinitionPostProcessor,InstantiationAwareBeanPostProcessorAdapter 类;
  • 应用启动的时候, 对于我们引入服务的类, Spring会进行对这些类进行依赖注入(类似@Autowired)
  • 依赖注入的时候会调用AnnotationInjectedBeanPostProcessor#postProcessPropertyValues()方法,这个方法里面使用了子类的处理逻辑,按照子类的处理逻辑进行依赖注入;
  • 在依赖注入前,会先执行MergedBeanDefinitionPostProcessor#postProcessMergedBeanDefinition方法, 子类AnnotationInjectedBeanPostProcessor实现了这个接口, 目的是扫描所有被@Reference注解修饰的方法和属性的准备工作;
publicclassReferenceAnnotationBeanPostProcessorextendsAnnotationInjectedBeanPostProcessorimplementsApplicationContextAware, ApplicationListener {//...}publicabstractclassAnnotationInjectedBeanPostProcessorextendsInstantiationAwareBeanPostProcessorAdapterimplementsMergedBeanDefinitionPostProcessor, PriorityOrdered,
        BeanFactoryAware, BeanClassLoaderAware, EnvironmentAware, DisposableBean {//...}publicabstractclassInstantiationAwareBeanPostProcessorAdapterimplementsSmartInstantiationAwareBeanPostProcessor{//....@Overridepublic PropertyValues postProcessPropertyValues(
            PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName)throws BeansException {return pvs;}}

MergedBeanDefinitionPostProcessor#postProcessMergedBeanDefinition方法

由子类AnnotationInjectedBeanPostProcessor 实现了这个方法;

publicinterfaceMergedBeanDefinitionPostProcessorextendsBeanPostProcessorvoidpostProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName);}publicabstractclassAnnotationInjectedBeanPostProcessorextendsInstantiationAwareBeanPostProcessorAdapterimplementsMergedBeanDefinitionPostProcessor, PriorityOrdered,
        BeanFactoryAware, BeanClassLoaderAware, EnvironmentAware, DisposableBean {//...@OverridepublicvoidpostProcessMergedBeanDefinition(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,接下来就会使用这个类去进行属性注入returnnewAnnotationInjectedBeanPostProcessor.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 =newLinkedList<AnnotationInjectedBeanPostProcessor.AnnotatedFieldElement>();
        ReflectionUtils.doWithFields(beanClass, field ->{for(Class<?extendsAnnotation> annotationType :getAnnotationTypes()){
                AnnotationAttributes attributes =getMergedAttributes(field, annotationType,getEnvironment(),true);if(attributes != null){//...
                    elements.add(newAnnotatedFieldElement(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 =newLinkedList<AnnotationInjectedBeanPostProcessor.AnnotatedMethodElement>();

        ReflectionUtils.doWithMethods(beanClass, method ->{

            Method bridgedMethod =findBridgedMethod(method);for(Class<?extendsAnnotation> 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(newAnnotatedMethodElement(method, pd, attributes));}}});return elements;}

获取完之后, 退出, 返回AnnotatedInjectionMetadata到(一)步骤中的调用处,然后会将这些Field和Method信息放入缓存;

postProcessPropertyValues

InstantiationAwareBeanPostProcessorAdapter抽象类已经定义好了该方法,子类AnnotationInjectedBeanPostProcessor 重写该方法,进行@Reference的依赖注入过程;

publicabstractclassInstantiationAwareBeanPostProcessorAdapterimplementsSmartInstantiationAwareBeanPostProcessor{@Overridepublic PropertyValues postProcessPropertyValues(
            PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName)throws BeansException {return pvs;}}}publicabstractclassAnnotationInjectedBeanPostProcessorextendsInstantiationAwareBeanPostProcessorAdapterimplementsMergedBeanDefinitionPostProcessor, PriorityOrdered,
        BeanFactoryAware, BeanClassLoaderAware, EnvironmentAware, DisposableBean {@Overridepublic 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. 执行属性注入;
publicvoidinject(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方法
publicclassAnnotatedFieldElementextendsInjectionMetadata.InjectedElement{}

inject工作:

  1. 获取Field的类型;
  2. 获取对象getInjectedObject
  3. 设置为可访问
  4. 反射给Field设值;
@Overrideprotectedvoidinject(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 - 创建一个代理对象返回;也就是意味着,最后注入的属性是一个代理对象;
@Overrideprotected 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();returngetOrCreateProxy(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 =newStringBuilder("ServiceBean");// Requiredappend(beanNameBuilder, interfaceClassName);// Optionalappend(beanNameBuilder, version);append(beanNameBuilder, group);// Build and remove last ":"
        String rawBeanName = beanNameBuilder.toString();// Resolve placeholdersreturn environment.resolvePlaceholders(rawBeanName);}
ReferenceAnnotationBeanPostProcessor#getReferenceBeanName

获取ReferenceBeanName名称字符串;
工作:

  1. 获取注解信息中的id属性;
  2. 判断id是否为空,为空 ;generateReferenceBeanName生成一个ReferenceBeanName字符串;
  3. 返回
private String getReferenceBeanName(AnnotationAttributes attributes, Class<?> interfaceClass){// id attribute appears since 2.7.3
        String beanName =getAttribute(attributes,"id");// beanName为null时会进入if判断if(!hasText(beanName)){
            beanName =generateReferenceBeanName(attributes, interfaceClass);}return beanName;}

generateReferenceBeanName生成一个ReferenceBeanName字符串;
工作:

  1. 获取@Reference注解信息所有属性项;
  2. 遍历属性项, 每个配置项以 “key = value ”的形式插入构造器字符串;
  3. 插入属性接口类型名称;
  4. 返回生成的ReferenceBeanName名称;
private String generateReferenceBeanName(AnnotationAttributes attributes, Class<?> interfaceClass){
        StringBuilder beanNameBuilder =newStringBuilder("@Reference");if(!attributes.isEmpty()){
            beanNameBuilder.append('(');for(Map.Entry<String, Object> entry : attributes.entrySet()){
                beanNameBuilder.append(entry.getKey()).append('=').append(entry.getValue()).append(',');}// replace the latest "," to be ")"
            beanNameBuilder.setCharAt(beanNameBuilder.lastIndexOf(","),')');}

        beanNameBuilder.append(" ").append(interfaceClass.getName());return beanNameBuilder.toString();}
referenceBeanName与referencedBeanName的区别

前者以 接口类路径名 + 版本号 + 组名 创建的;
后者以 注解所有信息 + 属性接口类型 创建的;

buildReferenceBeanIfAbsent(referenceBeanName, attributes, injectedType)

目的: 创建一个ReferenceBean对象实例;
工作 :

  1. 根据生成的referenceBeanName从缓存referenceBeanCache中获取ReferenceBean实例;
  2. 存在, 直接返回
  3. 不存在,调用ReferenceBeanBuilder#build()方法就创建一个ReferenceBean对象;
  4. 不存在, 创建完Reference实例后, 放入缓存中;
  5. 返回;
private ReferenceBean buildReferenceBeanIfAbsent(String referenceBeanName, AnnotationAttributes attributes, Class<?> referencedType)throws Exception {
        ReferenceBean<?> referenceBean = referenceBeanCache.get(referenceBeanName);if(referenceBean == null){// 生成了一个ReferenceBean对象,attributes是@Reference注解的参数值
            ReferenceBeanBuilder beanBuilder = ReferenceBeanBuilder
                    .create(attributes, applicationContext).interfaceClass(referencedType);
            referenceBean = beanBuilder.build();

            referenceBeanCache.put(referenceBeanName, referenceBean);}elseif(!referencedType.isAssignableFrom(referenceBean.getInterfaceClass())){//...}return referenceBean;}
ReferenceBeanBuilder#build()

创建一个Reference对象;
工作:

  1. 创建一个ReferenceBean对象
  2. 给ReferenceBean对象的属性赋值
publicfinal C build()throws Exception {checkDependencies();
        C configBean =doBuild();configureBean(configBean);//....return configBean;}
configureBean(C configBean)

作用: 设置ReferenceBean的属性;
工作:

  1. @Reference注解中的配置项赋值给configBean
  2. 配置注册中心;
  3. 配置监控中心;
  4. 配置Dubbo应用配置;
  5. 配置模块信息;
  6. 还是配置属性信息;
protectedvoidconfigureBean(C configBean)throws Exception {// preConfigureBean(attributes, configBean);configureRegistryConfigs(configBean);configureMonitorConfig(configBean);configureApplicationConfig(configBean);configureModuleConfig(configBean);// 设置applicationContext、interfaceName、consumer、methods属性,并调用ReferenceBean对象的afterPropertiesSet方法postConfigureBean(attributes, configBean);}//工作流程//1.创建数据绑定器, 这个是Spring的内容数据绑定技术;//2. 去空格;//3. 解析并设置parameter参数;//4. 使用数据绑定技术, 将@Reference的基本数据设置给ReferenceBean;@OverrideprotectedvoidpreConfigureBean(AnnotationAttributes attributes, ReferenceBean referenceBean){
    
        DataBinder dataBinder =newDataBinder(referenceBean);// Register CustomEditors for special fields// 去掉空格
        dataBinder.registerCustomEditor(String.class,"filter",newStringTrimmerEditor(true));
        dataBinder.registerCustomEditor(String.class,"listener",newStringTrimmerEditor(true));// 你可以这么配@Reference(parameters = {"text=123"})// 也可以这么配@Reference(parameters = {"text:123"})// 最终都会转变为Map设置到referenceBean中的parameters
        dataBinder.registerCustomEditor(Map.class,"parameters",newPropertyEditorSupport(){@OverridepublicvoidsetAsText(String text)throws java.lang.IllegalArgumentException {// Trim all whitespace
                String content = StringUtils.trimAllWhitespace(text);if(!StringUtils.hasText(content)){// No content , ignore directlyreturn;}// replace "=" to ","
                content = StringUtils.replace(content,"=",",");// replace ":" to ","
                content = StringUtils.replace(content,":",",");// String[] to Map
                Map<String, String> parameters = CollectionUtils.toStringMap(commaDelimitedListToStringArray(content));setValue(parameters);}});
        
        dataBinder.bind(newAnnotationPropertyValuesAdapter(attributes, applicationContext.getEnvironment(), IGNORE_FIELD_NAMES));}//工作流程://1. 设置上下文ApplicationContext;//2. 设置接口;//3. 设置ConsumerConfig配置; 对应的是 注解里面设置 的consumer 配置信息;//4. 设置Methodconfig配置//4. 调用afterPropertiesSet(), 还是设置属性星系;@OverrideprotectedvoidpostConfigureBean(AnnotationAttributes attributes, ReferenceBean bean)throws Exception {

        bean.setApplicationContext(applicationContext);configureInterface(attributes, bean);configureConsumerConfig(attributes, bean);configureMethodConfig(attributes, bean);

        bean.afterPropertiesSet();}publicvoidafterPropertiesSet()throws Exception {// 这个方法还是在给ReferenceBean对象的属性赋值if(applicationContext != null){
            BeanFactoryUtils.beansOfTypeIncludingAncestors(applicationContext, ConfigCenterBean.class,false,false);}// 如果@Reference注解中没有配置consumer参数if(getConsumer()== null){// 那么则从Spring容器中寻找ConsumerConfig类型的Bean, 比如通过@Bean定义了一个ConsumerConfig的Bean
            Map<String, ConsumerConfig> consumerConfigMap = applicationContext == null ? null : BeanFactoryUtils.beansOfTypeIncludingAncestors(applicationContext, ConsumerConfig.class,false,false);if(consumerConfigMap != null && consumerConfigMap.size()>0){
                ConsumerConfig consumerConfig = null;// 可能存在多个ConsumerConfig类型的Bean,遍历这些Bean,取第一个没有配置default或者default为true的Bean作为consumer的值for(ConsumerConfig config : consumerConfigMap.values()){if(config.isDefault()== null || config.isDefault()){if(consumerConfig != null){thrownewIllegalStateException("Duplicate consumer configs: "+ consumerConfig +" and "+ config);}
                        consumerConfig = config;}}if(consumerConfig != null){setConsumer(consumerConfig);}}}if(getApplication()== null
                &&(getConsumer()== null ||getConsumer().getApplication()== null)){
            Map<String, ApplicationConfig> applicationConfigMap = applicationContext == null ? null : BeanFactoryUtils.beansOfTypeIncludingAncestors(applicationContext, ApplicationConfig.class,false,false);if(applicationConfigMap != null && applicationConfigMap.size()>0){
                ApplicationConfig applicationConfig = null;for(ApplicationConfig config : applicationConfigMap.values()){if(applicationConfig != null){thrownewIllegalStateException("Duplicate application configs: "+ applicationConfig +" and "+ config);}
                    applicationConfig = config;}if(applicationConfig != null){setApplication(applicationConfig);}}}if(getModule()== null
                &&(getConsumer()== null ||getConsumer().getModule()== null)){
            Map<String, ModuleConfig> moduleConfigMap = applicationContext == null ? null : BeanFactoryUtils.beansOfTypeIncludingAncestors(applicationContext, ModuleConfig.class,false,false);if(moduleConfigMap != null && moduleConfigMap.size()>0){
                ModuleConfig moduleConfig = null;for(ModuleConfig config : moduleConfigMap.values()){if(config.isDefault()== null || config.isDefault()){if(moduleConfig != null){thrownewIllegalStateException("Duplicate module configs: "+ moduleConfig +" and "+ config);}
                        moduleConfig = config;}}if(moduleConfig != null){setModule(moduleConfig);}}}// 如果@Reference注解上没有配置registryIds// 那么则看application或consumer上有没有配置registryIdsif(StringUtils.isEmpty(getRegistryIds())){if(getApplication()!= null && StringUtils.isNotEmpty(getApplication().getRegistryIds())){setRegistryIds(getApplication().getRegistryIds());}if(getConsumer()!= null && StringUtils.isNotEmpty(getConsumer().getRegistryIds())){setRegistryIds(getConsumer().getRegistryIds());}}if(CollectionUtils.isEmpty(getRegistries())&&(getConsumer()== null || CollectionUtils.isEmpty(getConsumer().getRegistries()))&&(getApplication()== null || CollectionUtils.isEmpty(getApplication().getRegistries()))){
            Map<String, RegistryConfig> registryConfigMap = applicationContext == null ? null : BeanFactoryUtils.beansOfTypeIncludingAncestors(applicationContext, RegistryConfig.class,false,false);if(registryConfigMap != null && registryConfigMap.size()>0){
                List<RegistryConfig> registryConfigs =newArrayList<>();if(StringUtils.isNotEmpty(registryIds)){
                    Arrays.stream(COMMA_SPLIT_PATTERN.split(registryIds)).forEach(id ->{if(registryConfigMap.containsKey(id)){
                            registryConfigs.add(registryConfigMap.get(id));}});}if(registryConfigs.isEmpty()){for(RegistryConfig config : registryConfigMap.values()){if(StringUtils.isEmpty(registryIds)){
                            registryConfigs.add(config);}}}if(!registryConfigs.isEmpty()){super.setRegistries(registryConfigs);}}}if(getMetadataReportConfig()== null){
            Map<String, MetadataReportConfig> metadataReportConfigMap = applicationContext == null ? null : BeanFactoryUtils.beansOfTypeIncludingAncestors(applicationContext, MetadataReportConfig.class,false,false);if(metadataReportConfigMap != null && metadataReportConfigMap.size()==1){// first elementssuper.setMetadataReportConfig(metadataReportConfigMap.values().iterator().next());}elseif(metadataReportConfigMap != null && metadataReportConfigMap.size()>1){thrownewIllegalStateException("Multiple MetadataReport configs: "+ metadataReportConfigMap);}}// 如果@Reference注解中没有配置configCenter属性// 那么则从Spring容器中找ConfigCenterConfig类型的beanif(getConfigCenter()== null){
            Map<String, ConfigCenterConfig> configenterMap = applicationContext == null ? null : BeanFactoryUtils.beansOfTypeIncludingAncestors(applicationContext, ConfigCenterConfig.class,false,false);// 只能配一个ConfigCenterConfigif(configenterMap != null && configenterMap.size()==1){// 设置进去super.setConfigCenter(configenterMap.values().iterator().next());}elseif(configenterMap != null && configenterMap.size()>1){thrownewIllegalStateException("Multiple ConfigCenter found:"+ configenterMap);}}if(getMonitor()== null
                &&(getConsumer()== null ||getConsumer().getMonitor()== null)&&(getApplication()== null ||getApplication().getMonitor()== null)){
            Map<String, MonitorConfig> monitorConfigMap = applicationContext == null ? null : BeanFactoryUtils.beansOfTypeIncludingAncestors(applicationContext, MonitorConfig.class,false,false);if(monitorConfigMap != null && monitorConfigMap.size()>0){
                MonitorConfig monitorConfig = null;for(MonitorConfig config : monitorConfigMap.values()){if(config.isDefault()== null || config.isDefault()){if(monitorConfig != null){thrownewIllegalStateException("Duplicate monitor configs: "+ monitorConfig +" and "+ config);}
                        monitorConfig = config;}}if(monitorConfig != null){setMonitor(monitorConfig);}}}if(getMetrics()== null){
            Map<String, MetricsConfig> metricsConfigMap = applicationContext == null ? null : BeanFactoryUtils.beansOfTypeIncludingAncestors(applicationContext, MetricsConfig.class,false,false);if(metricsConfigMap != null && metricsConfigMap.size()>0){
                MetricsConfig metricsConfig = null;for(MetricsConfig config : metricsConfigMap.values()){if(metricsConfig != null){thrownewIllegalStateException("Duplicate metrics configs: "+ metricsConfig +" and "+ config);}
                    metricsConfig = config;}if(metricsConfig != null){setMetrics(metricsConfig);}}}if(shouldInit()){getObject();}}

registerReferenceBean(referencedBeanName, referenceBean, attributes, injectedType)

目的:将ReferenceBean注入容器, 这个步骤中,会将服务实现类注入容器,这样一个地方使用@Reference注解后,其他地方就可以通过@Autowired自动注入了。
工作:

  1. 获取Bean工厂;
  2. 获取referenceBeanName字符串, 将@Reference注解内容以键值对拼接 + 服务接口名; (应该是重复操作了)
  3. 判断容器是否已经存在这个Bean了。如果存在,则是本地服务(@Service注解修饰的服务在@Reference注解之前解析完成了)
  • 存在的话,则根据referenceBeanName去BeanFactory中获取 代表@Service注解的ServiceBean的BeanDefinition;
  • 获取ServiceBean的ref属性;
  • 获取ServiceBean的名称;
  • 注册别名,如果别名和ServiceBean的别名一样,就不需要注册别名, 不一样就以ServiceBean的Bean名称为键, referenceBeanName为值,放入别名缓冲中;
  • 不存在的话,就往容器中注入生成的referenceBean;
privatevoidregisterReferenceBean(String referencedBeanName, ReferenceBean referenceBean,
                                       AnnotationAttributes attributes,
                                       Class<?> interfaceClass){

        ConfigurableListableBeanFactory beanFactory =getBeanFactory();

        String beanName =getReferenceBeanName(attributes, interfaceClass);if(existsServiceBean(referencedBeanName)){// If @Service bean is local one
            AbstractBeanDefinition beanDefinition =(AbstractBeanDefinition) beanFactory.getBeanDefinition(referencedBeanName);
            RuntimeBeanReference runtimeBeanReference =(RuntimeBeanReference) beanDefinition.getPropertyValues().get("ref");// ServiceBean --- ref
            String serviceBeanName = runtimeBeanReference.getBeanName();
            beanFactory.registerAlias(serviceBeanName, beanName);}else{// Remote @Service Beanif(!beanFactory.containsBean(beanName)){
                beanFactory.registerSingleton(beanName, referenceBean);}}}

cacheInjectedReferenceBean(referenceBean, injectedElement)

目的: 将生成的referenceBean实例,放入缓存;

  • 如果是属性注入, 则放入injectedFieldReferenceBeanCache中;
  • 如果是方法注入, 则放入injectedMethodReferenceBeanCache中;
privatevoidcacheInjectedReferenceBean(ReferenceBean referenceBean,
                                            InjectionMetadata.InjectedElement injectedElement){if(injectedElement.getMember()instanceofField){
            injectedFieldReferenceBeanCache.put(injectedElement, referenceBean);}elseif(injectedElement.getMember()instanceofMethod){
            injectedMethodReferenceBeanCache.put(injectedElement, referenceBean);}}

getOrCreateProxy(referencedBeanName, referenceBeanName, referenceBean, injectedType)

目的: 创建一个代理对象返回;
为什么是代理对象,而不是上面容器中的服务实现类;
个人看法:
不同服务,分布在不同的机器上,如果是本地服务还好, 如果是远程服务, 在调用服务还需要额外操作,
例如负载均衡, 注册中心等功能;因此,不能直接返回服务实现类,而是返回代理对象, 公共的操作让代理对象去执行;

工作:

  1. 判断ServiceBean是否存在,存在则是本地服务, 不存在则是远程服务;
  2. 本地服务:会生成一个代理对象,代理对象的InvocationHandler会放入缓存中, 返回代理对象;
  3. 远程服务:调用get()获取一个代理对象返回;
private Object getOrCreateProxy(String referencedBeanName, String referenceBeanName, ReferenceBean referenceBean, Class<?> serviceInterfaceType){if(existsServiceBean(referencedBeanName)){// If the local @Service Bean exists, build a proxy of ReferenceBeanreturnnewProxyInstance(getClassLoader(),newClass[]{serviceInterfaceType},wrapInvocationHandler(referenceBeanName, referenceBean));}else{// ReferenceBean should be initialized and get immediately// 重点return referenceBean.get();}}private InvocationHandler wrapInvocationHandler(String referenceBeanName, ReferenceBean referenceBean){return localReferenceBeanInvocationHandlerCache.computeIfAbsent(referenceBeanName, name ->newReferenceBeanInvocationHandler(referenceBean));}

总结

@Reference注解服务引入的过程:

有了这些逻辑,@Reference注解服务引入的过程是这样的:

  1. 得到当前所引入服务对应的ServiceBean的beanName(源码中叫referencedBeanName)
  2. 根据@Reference注解的所有信息+属性接口类型得到一个referenceBeanName
  3. 根据referenceBeanName从referenceBeanCache获取对应的ReferenceBean,如果没有则创建一个ReferenceBean
  4. 根据referencedBeanName(ServiceBean的beanName)判断Spring容器中是否存在该bean,如果存在则给ref属性所对应的bean取一个别名,别名为referenceBeanName。 a. 如果Spring容器中不存在referencedBeanName对应的bean,则判断容器中是否存在referenceBeanName所对应的Bean,如果不存在则将创建出来的ReferenceBean注册到Spring容器中(此处这么做就支持了可以通过@Autowired注解也可以使用服务了,ReferenceBean是一个FactoryBean)
  5. 如果referencedBeanName存在对应的Bean,则额外生成一个代理对象,代理对象的InvocationHandler会缓存在localReferenceBeanInvocationHandlerCache中,这样如果引入的是同一个服务,并且这个服务在本地,
  6. 如果referencedBeanName不存在对应的Bean,则直接调用ReferenceBean的get()方法得到一个代理对象
标签: rpc dubbo java

本文转载自: https://blog.csdn.net/yaoyaochengxian/article/details/123298211
版权归原作者 ~玄霄- 所有, 如有侵权,请联系我们删除。

“Dubbo学习记录(八) -- Spring整合Dubbo中@Reference注解解析原理”的评论:

还没有评论