Spring源码解析:Autowired注解处理原理探讨(上)

2026-05-28 02:191阅读0评论SEO教程
  • 内容介绍
  • 文章标签
  • 相关推荐

本文共计2524个文字,预计阅读时间需要11分钟。

Spring源码解析:Autowired注解处理原理探讨(上)

描述:在AnnotationConfigApplicationContext上下文初始化时,会初始化一个AnnotatedBeanDefinitionReader类型的成员变量。此时,会通过AnnotationConfigUtils类中的registerAnnotationConfigProcessor方法进行注册。

概述

在 AnnotationConfigApplicationContext 上下文初始化的时候,会初始化一个 AnnotatedBeanDefinitionReader 类型的成员变量,在此期间,会通过 AnnotationConfigUtils 类中的​​registerAnnotationConfigProcessors​​方法,注册一些与注解配置相关的处理器。ConfigurationClassPostProcessor 就是其中之一。

本文通过阅读源码的方式,分析在这里注册的另外一个重要的处理器 AutowiredAnnotationBeanPostProcessor。

AutowiredAnnotationBeanPostProcessor 分析

先看 AutowiredAnnotationBeanPostProcessor 类的继承关系。

可以看出,它是一个 BeanPostProcessor,也就是 Bean 的后处理器。它还实现了一些 BeanPostProcessor 的字接口,BeanPostProcessor 和它的字接口中的方法,会在 Bean 实例初始化的过程中某些特定的时机被调用。所以,我们顺便了解一下这几个接口中包含的方法。

这里大概介绍一下其中一些关键方法的调用时机。

  • BeanPostProcessor
  • ​​postProcessBeforeInitialization​​ 在 Bean 实例的初始化方法执行前被调用。
  • ​​postProcessAfterInitialization​​ 在 Bean 实例的初始化方法执行后被调用。
  • MergedBeanDefinitionPostProcessor
  • ​​postProcessMergedBeanDefinition​​ 在通过​​doCreateBean​​使用反射机制创建 Bean 实例之后调用。
  • InstantiationAwareBeanPostProcessor
  • ​​postProcessBeforeInstantiation​​ 在​​doCreateBean​​执行前自定义 Bean 实例创建的扩展点。
  • ​​postProcessAfterInstantiation​​ 在​​postProcessBeforeInstantiation​​创建 Bean 实例不为空的情况下对 Bean 实例进行处理。
  • ​​postProcessProperties​​ 在装配 Bean 实例的属性前对属性进行处理。
  • SmartInstantiationAwareBeanPostProcessor
  • ​​getEarlyBeanReference​​ 用于在早期 Bean 实例被获取之前对其进行处理。
  • ​​determineCandidateConstructors​​ 用于在通过反射创建 Bean 实例是获取候选的构造函数。

再结合前面的类关系图,可以知道 AutowiredAnnotationBeanPostProcessor 对这些方法的实现,都可以从它本身和它的父类 InstantiationAwareBeanPostProcessorAdapter 中找到。在这两个类中,大部分的方法都继承了接口的默认实现,除了​​determineCandidateConstructors、postProcessMergedBeanDefinition​​、​​postProcessProperties​​三个方法。下面以这三个方法被调用的时机为顺序,分析这三个方法都做了什么。

​​determineCandidateConstructors​​方法分析

首先我们来分析​​determineCandidateConstructors​​方法,这个方法被调用的时机,是 Spring 通过反射创建 Bean 实例对象的时候,会通过这个方法来获取候选的构造方法。我们查看方法的源码。

代码量相当可观,我们接下来会挑重点分析。

Spring源码解析:Autowired注解处理原理探讨(上)

在第一个​​if​​语句块中,处理了​​@``Lookup​​注解相关的逻辑,这一部分不太重要,也很少会用到,因此不过介绍,我们重点看后面的部分。

// 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) {
// 省略语句块中的代码
}
}
}
return (candidateConstructors.length > 0 ? candidateConstructors : null);

首先,会从缓存集合candidateConstructorsCache中查询候选构造方法数组,如果缓存中获取的值不为空,则返回数组(数组中有元素)或者空(数组中没有元素)。另外,在​​if​​语句块中,还会在​​synchronized​​语句块中再次判断一遍。

确保缓存中确实没有内容的情况下,进入之后的流程。也就是上述代码中被省略的部分。

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

首先,会从当前 Bean 的类型中,获取到所有的构造方法,放到提前声明好的​​rawCandidates​​数组中。

List<Constructor<?>> candidates = new ArrayList<>(rawCandidates.length);
Constructor<?> requiredConstructor = null;
Constructor<?> defaultConstructor = null;
Constructor<?> primaryConstructor = BeanUtils.findPrimaryConstructor(beanClass);
int nonSyntheticConstructors = 0;

然后声明了一系列的变量,供后续的流程使用。这里的​​primaryConstructor​​主要是针对 Kotlin 的,如果是 Kotlin 类型,则会返回其主构造方法对应的 Java 构造方法,如果是 Java 类型,则为空。这里可以通过​​findPrimaryConstructor​​方法来看一下。

@Nullable
public static <T> Constructor<T> findPrimaryConstructor(Class<T> clazz) {
Assert.notNull(clazz, "Class must not be null");
if (KotlinDetector.isKotlinReflectPresent() && KotlinDetector.isKotlinType(clazz)) {
Constructor<T> kotlinPrimaryConstructor = KotlinDelegate.findPrimaryConstructor(clazz);
if (kotlinPrimaryConstructor != null) {
return kotlinPrimaryConstructor;
}
}
return null;
}

回到之前的方法中,之后开始对​​rawCandidates​​中的构造方法进行遍历。

for (Constructor<?> candidate : rawCandidates) {
// ...
}

接下来看​​for​​循环语句块中的内容。

if (!candidate.isSynthetic()) {
nonSyntheticConstructors++;
}
else if (primaryConstructor != null) {
continue;
}

首先判断了当前的构造方法是不是「合成」的构造方法,不是的话​​nonSyntheticConstructors​​变量自增,如果是,且​​primaryConstructor​​不是空,则跳过档次循环。

MergedAnnotation<?> 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​​注解,不仅会从当前的构造方法上查找,如果当前的类是CGLIB代理类型,还会从其​​userClass​​,也就是用户声明的类中查找。

如果当前的构造方法没有被标记​​@``Autowired​​注解,则​​ann​​变量为空,反之则不为空。获取完成之后,会进入一个​​if-else​​语句,针对​​ann​​是否为空的情况,执行不同的流程。

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

如果​​ann​​不为空,则进入以上的代码块中。首先会通过其中的第一个​​if​​语句判断​​requiredConstructor​​是否为空,如果不是空的话会抛出异常。当循环第一次走到这里的时候,它一定是空的,我们接着往下看。

接下来会判断当前构造方法的​​@``Autowired​​注解的​​required​​属性是否为​​true​​。如果是true的话,则会进入下一个​​if​​语句块。因为如果有构造方法的​​@``Autowired​​注解的​​required​​属性是否为​​true​​的时候,被注解标记的构造方法只能有一个,所以,如果当前的构造方法如果符合条件,但是​​candidates​​不为空,则会抛出异常。确保没有异常之后,会将当前的构造方法赋值给​​requiredConstructor​​变量。

最后,只要当前的构造方法被标记了​​@``Autowired​​注解,都会被添加到​​candidates​​集合中。

如果当前的构造方法没有被标记​​@``Autowired​​注解,且构造方法是无参构造方法,则将其赋值给​​defaultConstructor​​变量。

else if (candidate.getParameterCount() == 0) {
defaultConstructor = candidate;
}

至此,遍历所有构造方法的​​for​​循环就执行完了。接下来会进入一系列的条件判断语句,它们的主要作用是对之前遍历过程中得到的结果进行处理。

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

如果​​candidates​​不为空,也就是存在被标记​​@``Autowired​​注解的构造方法,则进入当前的语句块。

再次判断,如果​​requiredConstructor​​为空,也就是不存在​​@``Autowired​​注解的​​required​​属性是否为​​true​​的构造方法,则将默认构造方法(也就是空参的构造发方法)​​defaultConstructor​​添加到​​candidates​​中。

当前if语句块的最后,将​​candidates​​转换为数组赋值给​​candidateConstructors​​作为候选的构造方法数组。

如果​​candidates​​为空,则进入后续的条件判断语句块。

else if (rawCandidates.length == 1 && rawCandidates[0].getParameterCount() > 0) {
candidateConstructors = new Constructor<?>[] {rawCandidates[0]};
}
else if (nonSyntheticConstructors == 2 && primaryConstructor != null &&
defaultConstructor != null && !primaryConstructor.equals(defaultConstructor)) {
candidateConstructors = new Constructor<?>[] {primaryConstructor, defaultConstructor};
}
else if (nonSyntheticConstructors == 1 && primaryConstructor != null) {
candidateConstructors = new Constructor<?>[] {primaryConstructor};
}
else {
candidateConstructors = new Constructor<?>[0];
}

后续的几个条件连起来看。

  • 如果当前类型只有一个构造方法,且是有参数的构造方法,则​​candidateConstructors​​为之包含这个构造方法的数组。
  • 如果只有两个非合成的构造方法,其中一个是默认构造方法​​defaultConstructor​​,另一个是​​primaryConstructor​​,且两者不是同一个构造方法,则​​candidateConstructors​​为包含这两者的数组,​​primaryConstructor​​在​​defaultConstructor​​之前。
  • 如果只有一个​​primaryConstructor​​,则​​candidateConstructors​​是之包含它的数组。
  • 如果之前的条件都不符合,则​​candidateConstructors​​为空数组。
  • 处理完之后,会将结果放到缓存中。

    this.candidateConstructorsCache.put(beanClass, candidateConstructors);

    在方法的最后,会判断​​candidateConstructors​​是否有元素,如果有则返回,没有就返回空。

    return (candidateConstructors.length > 0 ? candidateConstructors : null);

    总结

    本文介绍了 AutowiredAnnotationBeanPostProcessor 后处理器中的​​determineCandidateConstructors​​如何为 Bean 类型确定候选的构造函数。

    本文共计2524个文字,预计阅读时间需要11分钟。

    Spring源码解析:Autowired注解处理原理探讨(上)

    描述:在AnnotationConfigApplicationContext上下文初始化时,会初始化一个AnnotatedBeanDefinitionReader类型的成员变量。此时,会通过AnnotationConfigUtils类中的registerAnnotationConfigProcessor方法进行注册。

    概述

    在 AnnotationConfigApplicationContext 上下文初始化的时候,会初始化一个 AnnotatedBeanDefinitionReader 类型的成员变量,在此期间,会通过 AnnotationConfigUtils 类中的​​registerAnnotationConfigProcessors​​方法,注册一些与注解配置相关的处理器。ConfigurationClassPostProcessor 就是其中之一。

    本文通过阅读源码的方式,分析在这里注册的另外一个重要的处理器 AutowiredAnnotationBeanPostProcessor。

    AutowiredAnnotationBeanPostProcessor 分析

    先看 AutowiredAnnotationBeanPostProcessor 类的继承关系。

    可以看出,它是一个 BeanPostProcessor,也就是 Bean 的后处理器。它还实现了一些 BeanPostProcessor 的字接口,BeanPostProcessor 和它的字接口中的方法,会在 Bean 实例初始化的过程中某些特定的时机被调用。所以,我们顺便了解一下这几个接口中包含的方法。

    这里大概介绍一下其中一些关键方法的调用时机。

    • BeanPostProcessor
    • ​​postProcessBeforeInitialization​​ 在 Bean 实例的初始化方法执行前被调用。
    • ​​postProcessAfterInitialization​​ 在 Bean 实例的初始化方法执行后被调用。
    • MergedBeanDefinitionPostProcessor
    • ​​postProcessMergedBeanDefinition​​ 在通过​​doCreateBean​​使用反射机制创建 Bean 实例之后调用。
    • InstantiationAwareBeanPostProcessor
    • ​​postProcessBeforeInstantiation​​ 在​​doCreateBean​​执行前自定义 Bean 实例创建的扩展点。
    • ​​postProcessAfterInstantiation​​ 在​​postProcessBeforeInstantiation​​创建 Bean 实例不为空的情况下对 Bean 实例进行处理。
    • ​​postProcessProperties​​ 在装配 Bean 实例的属性前对属性进行处理。
    • SmartInstantiationAwareBeanPostProcessor
    • ​​getEarlyBeanReference​​ 用于在早期 Bean 实例被获取之前对其进行处理。
    • ​​determineCandidateConstructors​​ 用于在通过反射创建 Bean 实例是获取候选的构造函数。

    再结合前面的类关系图,可以知道 AutowiredAnnotationBeanPostProcessor 对这些方法的实现,都可以从它本身和它的父类 InstantiationAwareBeanPostProcessorAdapter 中找到。在这两个类中,大部分的方法都继承了接口的默认实现,除了​​determineCandidateConstructors、postProcessMergedBeanDefinition​​、​​postProcessProperties​​三个方法。下面以这三个方法被调用的时机为顺序,分析这三个方法都做了什么。

    ​​determineCandidateConstructors​​方法分析

    首先我们来分析​​determineCandidateConstructors​​方法,这个方法被调用的时机,是 Spring 通过反射创建 Bean 实例对象的时候,会通过这个方法来获取候选的构造方法。我们查看方法的源码。

    代码量相当可观,我们接下来会挑重点分析。

    Spring源码解析:Autowired注解处理原理探讨(上)

    在第一个​​if​​语句块中,处理了​​@``Lookup​​注解相关的逻辑,这一部分不太重要,也很少会用到,因此不过介绍,我们重点看后面的部分。

    // 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) {
    // 省略语句块中的代码
    }
    }
    }
    return (candidateConstructors.length > 0 ? candidateConstructors : null);

    首先,会从缓存集合candidateConstructorsCache中查询候选构造方法数组,如果缓存中获取的值不为空,则返回数组(数组中有元素)或者空(数组中没有元素)。另外,在​​if​​语句块中,还会在​​synchronized​​语句块中再次判断一遍。

    确保缓存中确实没有内容的情况下,进入之后的流程。也就是上述代码中被省略的部分。

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

    首先,会从当前 Bean 的类型中,获取到所有的构造方法,放到提前声明好的​​rawCandidates​​数组中。

    List<Constructor<?>> candidates = new ArrayList<>(rawCandidates.length);
    Constructor<?> requiredConstructor = null;
    Constructor<?> defaultConstructor = null;
    Constructor<?> primaryConstructor = BeanUtils.findPrimaryConstructor(beanClass);
    int nonSyntheticConstructors = 0;

    然后声明了一系列的变量,供后续的流程使用。这里的​​primaryConstructor​​主要是针对 Kotlin 的,如果是 Kotlin 类型,则会返回其主构造方法对应的 Java 构造方法,如果是 Java 类型,则为空。这里可以通过​​findPrimaryConstructor​​方法来看一下。

    @Nullable
    public static <T> Constructor<T> findPrimaryConstructor(Class<T> clazz) {
    Assert.notNull(clazz, "Class must not be null");
    if (KotlinDetector.isKotlinReflectPresent() && KotlinDetector.isKotlinType(clazz)) {
    Constructor<T> kotlinPrimaryConstructor = KotlinDelegate.findPrimaryConstructor(clazz);
    if (kotlinPrimaryConstructor != null) {
    return kotlinPrimaryConstructor;
    }
    }
    return null;
    }

    回到之前的方法中,之后开始对​​rawCandidates​​中的构造方法进行遍历。

    for (Constructor<?> candidate : rawCandidates) {
    // ...
    }

    接下来看​​for​​循环语句块中的内容。

    if (!candidate.isSynthetic()) {
    nonSyntheticConstructors++;
    }
    else if (primaryConstructor != null) {
    continue;
    }

    首先判断了当前的构造方法是不是「合成」的构造方法,不是的话​​nonSyntheticConstructors​​变量自增,如果是,且​​primaryConstructor​​不是空,则跳过档次循环。

    MergedAnnotation<?> 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​​注解,不仅会从当前的构造方法上查找,如果当前的类是CGLIB代理类型,还会从其​​userClass​​,也就是用户声明的类中查找。

    如果当前的构造方法没有被标记​​@``Autowired​​注解,则​​ann​​变量为空,反之则不为空。获取完成之后,会进入一个​​if-else​​语句,针对​​ann​​是否为空的情况,执行不同的流程。

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

    如果​​ann​​不为空,则进入以上的代码块中。首先会通过其中的第一个​​if​​语句判断​​requiredConstructor​​是否为空,如果不是空的话会抛出异常。当循环第一次走到这里的时候,它一定是空的,我们接着往下看。

    接下来会判断当前构造方法的​​@``Autowired​​注解的​​required​​属性是否为​​true​​。如果是true的话,则会进入下一个​​if​​语句块。因为如果有构造方法的​​@``Autowired​​注解的​​required​​属性是否为​​true​​的时候,被注解标记的构造方法只能有一个,所以,如果当前的构造方法如果符合条件,但是​​candidates​​不为空,则会抛出异常。确保没有异常之后,会将当前的构造方法赋值给​​requiredConstructor​​变量。

    最后,只要当前的构造方法被标记了​​@``Autowired​​注解,都会被添加到​​candidates​​集合中。

    如果当前的构造方法没有被标记​​@``Autowired​​注解,且构造方法是无参构造方法,则将其赋值给​​defaultConstructor​​变量。

    else if (candidate.getParameterCount() == 0) {
    defaultConstructor = candidate;
    }

    至此,遍历所有构造方法的​​for​​循环就执行完了。接下来会进入一系列的条件判断语句,它们的主要作用是对之前遍历过程中得到的结果进行处理。

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

    如果​​candidates​​不为空,也就是存在被标记​​@``Autowired​​注解的构造方法,则进入当前的语句块。

    再次判断,如果​​requiredConstructor​​为空,也就是不存在​​@``Autowired​​注解的​​required​​属性是否为​​true​​的构造方法,则将默认构造方法(也就是空参的构造发方法)​​defaultConstructor​​添加到​​candidates​​中。

    当前if语句块的最后,将​​candidates​​转换为数组赋值给​​candidateConstructors​​作为候选的构造方法数组。

    如果​​candidates​​为空,则进入后续的条件判断语句块。

    else if (rawCandidates.length == 1 && rawCandidates[0].getParameterCount() > 0) {
    candidateConstructors = new Constructor<?>[] {rawCandidates[0]};
    }
    else if (nonSyntheticConstructors == 2 && primaryConstructor != null &&
    defaultConstructor != null && !primaryConstructor.equals(defaultConstructor)) {
    candidateConstructors = new Constructor<?>[] {primaryConstructor, defaultConstructor};
    }
    else if (nonSyntheticConstructors == 1 && primaryConstructor != null) {
    candidateConstructors = new Constructor<?>[] {primaryConstructor};
    }
    else {
    candidateConstructors = new Constructor<?>[0];
    }

    后续的几个条件连起来看。

  • 如果当前类型只有一个构造方法,且是有参数的构造方法,则​​candidateConstructors​​为之包含这个构造方法的数组。
  • 如果只有两个非合成的构造方法,其中一个是默认构造方法​​defaultConstructor​​,另一个是​​primaryConstructor​​,且两者不是同一个构造方法,则​​candidateConstructors​​为包含这两者的数组,​​primaryConstructor​​在​​defaultConstructor​​之前。
  • 如果只有一个​​primaryConstructor​​,则​​candidateConstructors​​是之包含它的数组。
  • 如果之前的条件都不符合,则​​candidateConstructors​​为空数组。
  • 处理完之后,会将结果放到缓存中。

    this.candidateConstructorsCache.put(beanClass, candidateConstructors);

    在方法的最后,会判断​​candidateConstructors​​是否有元素,如果有则返回,没有就返回空。

    return (candidateConstructors.length > 0 ? candidateConstructors : null);

    总结

    本文介绍了 AutowiredAnnotationBeanPostProcessor 后处理器中的​​determineCandidateConstructors​​如何为 Bean 类型确定候选的构造函数。