spring 自动注入AutowiredAnnotationBeanPostProcessor源码解析

 更新时间:2023年03月07日 11:06:35   作者:无名之辈J  
这篇文章主要介绍了spring自动注入AutowiredAnnotationBeanPostProcessor源码解析,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪

一、MergedBeanDefinitionPostProcessor

1.1、postProcessMergedBeanDefinition

在Bean属性赋值前,缓存属性字段上的@Autowired和@Value注解信息。

public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) {
   //1.1.1 查询属性或方法上有@Value和@Autowired注解的元素
   InjectionMetadata metadata = findAutowiringMetadata(beanName, beanType, null);
   //1.1.2 检查元数据信息
   metadata.checkConfigMembers(beanDefinition);
}

1.1.1 findAutowiringMetadata 查询属性或方法上有@Value和@Autowired注解的元素

private InjectionMetadata findAutowiringMetadata(String beanName, Class<?> clazz, @Nullable PropertyValues pvs) {
   // Fall back to class name as cache key, for backwards compatibility with custom callers.
   //获取Bean名称作为缓存key
   String cacheKey = (StringUtils.hasLength(beanName) ? beanName : clazz.getName());
   // Quick check on the concurrent map first, with minimal locking.
   //使用双重检查机制获取缓存
   InjectionMetadata 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);
            }
            //构建元数据
            metadata = buildAutowiringMetadata(clazz);
            this.injectionMetadataCache.put(cacheKey, metadata);
         }
      }
   }
   return metadata;
}

这个 do-while 循环是用来一步一步往父类上爬的(可以看到这个循环体的最后一行是获取父类,判断条件是判断是否爬到了 Object

private InjectionMetadata buildAutowiringMetadata(final Class<?> clazz) {
    // 判断是不是候选者类,比如说类名是以 java.开头的则不是候选者类 Order的实现类也不是候选者类
    // 但是如果this.autowiredAnnotationTypes 中有以java.开头的注解就返回true了
   if (!AnnotationUtils.isCandidateClass(clazz, this.autowiredAnnotationTypes)) {
      return InjectionMetadata.EMPTY;
   }
   List<InjectionMetadata.InjectedElement> elements = new ArrayList<>();
   Class<?> targetClass = clazz;
   do {
      final List<InjectionMetadata.InjectedElement> currElements = new ArrayList<>();
      // 循环获取类上的属性,如果类属性上有@Value和@Autowired包装成AutowiredFieldElement放入结果集  
      ReflectionUtils.doWithLocalFields(targetClass, field -> {
         MergedAnnotation<?> ann = findAutowiredAnnotation(field);
         if (ann != null) {
            if (Modifier.isStatic(field.getModifiers())) {
               if (logger.isInfoEnabled()) {
                  logger.info("Autowired annotation is not supported on static fields: " + field);
               }
               return;
            }
            boolean required = determineRequiredStatus(ann);
            currElements.add(new AutowiredFieldElement(field, required));
         }
      });
      // 循环获取类上的方法,如果类方法上有@Value和@Autowired包装成AutowiredMethodElement放入结果集
      ReflectionUtils.doWithLocalMethods(targetClass, method -> {
         Method bridgedMethod = BridgeMethodResolver.findBridgedMethod(method);
         if (!BridgeMethodResolver.isVisibilityBridgeMethodPair(method, bridgedMethod)) {
            return;
         }
         MergedAnnotation<?> ann = findAutowiredAnnotation(bridgedMethod);
         if (ann != null && method.equals(ClassUtils.getMostSpecificMethod(method, clazz))) {
            if (Modifier.isStatic(method.getModifiers())) {
               if (logger.isInfoEnabled()) {
                  logger.info("Autowired annotation is not supported on static methods: " + method);
               }
               return;
            }
            if (method.getParameterCount() == 0) {
               if (logger.isInfoEnabled()) {
                  logger.info("Autowired annotation should only be used on methods with parameters: " +
                        method);
               }
            }
            boolean required = determineRequiredStatus(ann);
            PropertyDescriptor pd = BeanUtils.findPropertyForMethod(bridgedMethod, clazz);
            currElements.add(new AutowiredMethodElement(method, required, pd));
         }
      });
      elements.addAll(0, currElements);
      targetClass = targetClass.getSuperclass();
   }
   while (targetClass != null && targetClass != Object.class);
   return InjectionMetadata.forElements(elements, clazz);
}

1.1.2 检查元数据信息

检查是否有重复的元数据,去重处理,如一个属性上既有@Autowired注解,又有@Resource注解 。只使用一种方式进行注入,由于@Resource先进行解析,所以会选择@Resource的方式

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);
         if (logger.isTraceEnabled()) {
            logger.trace("Registered injected element on class [" + this.targetClass.getName() + "]: " + element);
         }
      }
   }
   this.checkedElements = checkedElements;
}

二、SmartInstantiationAwareBeanPostProcessor

2.1、determineCandidateConstructors

在bean实例化前选择@Autowired注解的构造函数,同时注入属性,从而完成自定义构造函数的选择。

public Constructor<?>[] determineCandidateConstructors(Class<?> beanClass, final String beanName)
            throws BeanCreationException {
        // Let's check for lookup methods here...
        if (!this.lookupMethodsChecked.contains(beanName)) {
            try {
                ReflectionUtils.doWithMethods(beanClass, method -> {
                    Lookup lookup = method.getAnnotation(Lookup.class);
                    if (lookup != null) {
                        Assert.state(this.beanFactory != null, "No BeanFactory available");
                        LookupOverride override = new LookupOverride(method, lookup.value());
                        try {
                            RootBeanDefinition mbd = (RootBeanDefinition)
                                    this.beanFactory.getMergedBeanDefinition(beanName);
                            mbd.getMethodOverrides().addOverride(override);
                        }
                        catch (NoSuchBeanDefinitionException ex) {
                            throw new BeanCreationException(beanName,
                                    "Cannot apply @Lookup to beans without corresponding bean definition");
                        }
                    }
                });
            }
            catch (IllegalStateException ex) {
                throw new BeanCreationException(beanName, "Lookup method resolution failed", ex);
            }
            this.lookupMethodsChecked.add(beanName);
        }
        // Quick check on the concurrent map first, with minimal locking.
        Constructor<?>[] candidateConstructors = this.candidateConstructorsCache.get(beanClass);
        if (candidateConstructors == null) {
            // Fully synchronized resolution now...
            synchronized (this.candidateConstructorsCache) {
                candidateConstructors = this.candidateConstructorsCache.get(beanClass);
                if (candidateConstructors == null) {
                    Constructor<?>[] rawCandidates;
                    try {
                        //反射获取所有构造函数
                        rawCandidates = beanClass.getDeclaredConstructors();
                    }
                    catch (Throwable ex) {
                        throw new BeanCreationException(beanName,
                                "Resolution of declared constructors on bean Class [" + beanClass.getName() +
                                        "] from ClassLoader [" + beanClass.getClassLoader() + "] failed", ex);
                    }
                    //候选构造方法
                    List<Constructor<?>> candidates = new ArrayList<>(rawCandidates.length);
                    Constructor<?> requiredConstructor = null;
                    Constructor<?> defaultConstructor = null;
                    //这个貌似是 Kotlin 上用的, 不用管它
                    Constructor<?> primaryConstructor = BeanUtils.findPrimaryConstructor(beanClass);
                    int nonSyntheticConstructors = 0;
                    //遍历这些构造函数
                    for (Constructor<?> candidate : rawCandidates) {
                        //判断构造方法是否是合成的
                        if (!candidate.isSynthetic()) {
                            nonSyntheticConstructors++;
                        }
                        else if (primaryConstructor != null) {
                            continue;
                        }
                        //查看是否有 @Autowired 注解
                        //如果有多个构造方法, 可以通过标注 @Autowired 的方式来指定使用哪个构造方法
                        AnnotationAttributes ann = findAutowiredAnnotation(candidate);
                        if (ann == null) {
                            Class<?> userClass = ClassUtils.getUserClass(beanClass);
                            if (userClass != beanClass) {
                                try {
                                    Constructor<?> superCtor =
                                            userClass.getDeclaredConstructor(candidate.getParameterTypes());
                                    ann = findAutowiredAnnotation(superCtor);
                                }
                                catch (NoSuchMethodException ex) {
                                    // Simply proceed, no equivalent superclass constructor found...
                                }
                            }
                        }
                        //有 @Autowired 的情况
                        if (ann != null) {
                            if (requiredConstructor != null) {
                                throw new BeanCreationException(beanName,
                                        "Invalid autowire-marked constructor: " + candidate +
                                                ". Found constructor with 'required' Autowired annotation already: " +
                                                requiredConstructor);
                            }
                            boolean required = determineRequiredStatus(ann);
                            if (required) {
                                if (!candidates.isEmpty()) {
                                    throw new BeanCreationException(beanName,
                                            "Invalid autowire-marked constructors: " + candidates +
                                                    ". Found constructor with 'required' Autowired annotation: " +
                                                    candidate);
                                }
                                requiredConstructor = candidate;
                            }
                            candidates.add(candidate);
                        }
                        //无参构造函数的情况
                        else if (candidate.getParameterCount() == 0) {
                            //构造函数没有参数, 则设置为默认的构造函数
                            defaultConstructor = candidate;
                        }
                    }
                    //到这里, 已经循环完了所有的构造方法
                    //候选者不为空时
                    if (!candidates.isEmpty()) {
                        // Add default constructor to list of optional constructors, as fallback.
                        if (requiredConstructor == null) {
                            if (defaultConstructor != null) {
                                candidates.add(defaultConstructor);
                            }
                            else if (candidates.size() == 1 && logger.isInfoEnabled()) {
                                logger.info("Inconsistent constructor declaration on bean with name '" + beanName +
                                        "': single autowire-marked constructor flagged as optional - " +
                                        "this constructor is effectively required since there is no " +
                                        "default constructor to fall back to: " + candidates.get(0));
                            }
                        }
                        candidateConstructors = candidates.toArray(new Constructor<?>[0]);
                    }
                    //类的构造方法只有1个, 且该构造方法有多个参数
                    else if (rawCandidates.length == 1 && rawCandidates[0].getParameterCount() > 0) {
                        candidateConstructors = new Constructor<?>[] {rawCandidates[0]};
                    }
                    //这里不会进, 因为 primaryConstructor = null
                    else if (nonSyntheticConstructors == 2 && primaryConstructor != null &&
                            defaultConstructor != null && !primaryConstructor.equals(defaultConstructor)) {
                        candidateConstructors = new Constructor<?>[] {primaryConstructor, defaultConstructor};
                    }
                    //这里也不会进, 因为 primaryConstructor = null
                    else if (nonSyntheticConstructors == 1 && primaryConstructor != null) {
                        candidateConstructors = new Constructor<?>[] {primaryConstructor};
                    }
                    else {
                        //如果方法进了这里, 就是没找到合适的构造方法
                        //1. 类定义了多个构造方法, 且没有 @Autowired , 则有可能会进这里
                        candidateConstructors = new Constructor<?>[0];
                    }
                    this.candidateConstructorsCache.put(beanClass, candidateConstructors);
                }
            }
        }
   //这里如果没找到, 则会返回 null, 而不会返回空数组
        return (candidateConstructors.length > 0 ? candidateConstructors : null);
    }

遍历构造方法:

  • 只有一个无参构造方法, 则返回null
  • 只有一个有参构造方法, 则返回这个构造方法
  • 有多个构造方法且没有@Autowired, 此时spring则会蒙圈了, 不知道使用哪一个了。这里的后置处理器智能选择构造方法后置处理器。当选择不了的时候, 干脆返回 null
  • 有多个构造方法, 且在其中一个方法上标注了 @Autowired , 则会返回这个标注的构造方法
  • 有多个构造方法, 且在多个方法上标注了@Autowired, 则spring会抛出异常, Spring会认为, 你指定了几个给我, 是不是你弄错了

注意:

这地方有个问题需要注意一下, 如果你写了多个构造方法, 且没有写 无参构造方法, 那么此处返回null, 

在回到 createBeanInstance 方法中, 如果不能走 autowireConstructor(), 而走到 instantiateBean() 中去的话, 会报错的,因为类已经没有无参构造函数了。

以上就是AutowiredAnnotationBeanPostProcessor源码解析的详细内容,更多关于AutowiredAnnotationBeanPostProcessor的资料请关注脚本之家其它相关文章!

相关文章

  • 解决Javaweb 提交表单到servlet时出现空白页面,但网站不报错问题

    解决Javaweb 提交表单到servlet时出现空白页面,但网站不报错问题

    这篇文章主要介绍了解决Javaweb 提交表单到servlet时出现空白页面,但网站不报错的问题,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-08-08
  • Mybatis中流式查询的实现示例

    Mybatis中流式查询的实现示例

    MyBatis的ResultHandler是用于处理数据库查询结果集的工具,可以通过回调函数对数据进行流式处理,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2024-09-09
  • java获取机器码简单实现demo

    java获取机器码简单实现demo

    这篇文章主要为大家介绍了java获取机器码的简单实现demo,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-11-11
  • Java创建线程及配合使用Lambda方式

    Java创建线程及配合使用Lambda方式

    这篇文章主要介绍了Java创建线程及配合使用Lambda方式,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-08-08
  • java使用枚举封装错误码及错误信息详解

    java使用枚举封装错误码及错误信息详解

    这篇文章主要介绍了java使用枚举封装错误码及错误信息,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-12-12
  • 解决java.util.NoSuchElementException异常的问题

    解决java.util.NoSuchElementException异常的问题

    这篇文章主要介绍了解决java.util.NoSuchElementException异常的问题,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2020-09-09
  • java中字符串与日期的转换实例

    java中字符串与日期的转换实例

    java中字符串与日期的转换实例,需要的朋友可以参考一下
    2013-05-05
  • Java规则引擎Easy Rules的使用介绍

    Java规则引擎Easy Rules的使用介绍

    这篇文章主要介绍了Java规则引擎Easy Rules的使用介绍,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-06-06
  • 浅谈java泛型的作用及其基本概念

    浅谈java泛型的作用及其基本概念

    下面小编就为大家带来一篇浅谈java泛型的作用及其基本概念。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2016-08-08
  • 详解Mybatis多参数传递入参四种处理方式

    详解Mybatis多参数传递入参四种处理方式

    这篇文章主要介绍了详解Mybatis多参数传递入参四种处理方式,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2021-04-04

最新评论