Spring 源码解析——IOC 源码解析(BeanPostProcessor 系列之 AutowiredAnnotationBeanPostProcessor)(五)

写文章不易,转载请标明出处。

同时,如果你喜欢我的文章,请关注我,让我们一起进步。

一、概述

在前面的一篇博文中我们已经分析了 ApplicationContextAwareProcessor 这个 BeanPostProcessor 实现类,在这篇博文中我们将继续前行来分析 Spring 当中另一个至关重要的 AutowiredAnnotationBeanPostProcessor,这个 BeanPostProcessor 实现了 Spring 当中最重要的属性自动注入功能,与其相关联的就是我们最常见也是最常使用的 @Autowired 注解。

在开始之前还是先絮叨絮叨一些闲话,本来这个 BeanPostProcessor 系列解析博文是想按照上篇博文中的顺序来进行的,但是在早上起来的时候突然回想起前段时间的那个 Bean 单例循环依赖解决方案,突然对 @Autowired 注解充满了兴趣,很好奇它的内部是怎么实现的,因此临时决定将对于 AutowiredAnnotationBeanPostProcessor 的解析博文往前提一些。

最后在开始之前声明一下,对于 AutowiredAnnotationBeanPostProcessor 是 Spring 当中特别重要的一个类,它的实现涉及了 Spring 的 DI 核心功能(并且包括部分对于注入方式的选取过程),为了能够对 AutowiredAnnotationBeanPostProcessor 进行一个全方位多角度的详细解析这篇博文的篇幅可能会很长,大概的编写思路就是先通过官方文档的阅读了解 @Autowired 的功能,然后是 AutowiredAnnotationBeanPostProcessor 类的功能,然后是对于 AutowiredAnnotationBeanPostProcessor 这个类源码的单独解析,最后才是去分析它在 Spring 当中的被调用流程,不过我相信经过这篇博文的洗礼,你一定会对 Spring 的自动注入有一个更深刻且更清晰的了解,下面就开始正文。

二、功能分析(官方文档解析)

首先,对于功能的分析,我想强调的一点就是任何抛开官方文档谈功能的分析都是耍流氓,因此本着认真负责并且不做流氓的态度,我们所有的分析都会基于官方文档,在这里我们会重点分析官方文档中对于 @Autowired 注解和 AutowiredAnnotationBeanPostProcessor 类的功能介绍。

2.1 @Autowire 注解

https://docs.spring.io/spring-framework/docs/current/spring-framework-reference/core.html#beans-autowired-annotation

 @Autowired 是我们经常使用的一个 Spring 注解,主要的功能就是完成 Spring 当中的 Bean 自动注入工作,对于 @Autowired 的使用方法一般有下面几种:

(1)可以将 @Autowired 注解应用于构造函数,从 Spring Framework 4.3 开始,如果目标 Bean 只定义了一个构造函数,那么就不再需要在这样的构造函数上使用 @Autowired 注解。但是,如果有多个构造函数可用,则必须至少注释一个构造函数,以便告诉容器使用哪个构造函数;

(2)还可以将 @Autowired 注解应用于传统的 setter 方法

(3)还可以将 @Autowired 注解应用于具有任意名称和多个参数的方法

(4)还可以将 @Autowired 注解应用于属性,甚至可以将它与构造函数混合使用,当 @Autowired 注解作用于属性时,属性的类型可以为数组或列表等,且当属性的类型为数组(数组元素为某个指定类型时)或类型集合(泛型语法 <>)时,可以从 ApplicationContext 中获取指定类型的所有 Bean,例如当 @Autowired 所作用的属性类型为 Entity[] 或类似于 Set<Entity> 的泛型集合时,可以获取到容器中所有类型为 Entity 的 Bean(@Autowired 默认为 autowired by type)。

但是需要注意的是上述数组或集合中 Bean 的循序是按照其 BeanDefinition 在容器中的注册顺序进行排列的,如果我们想要指定它们的顺序,需要使用 @Order(会影响注入点的优先级,但是不会影响单例启动顺序)或 @Priority 注解。还有一种情况即当属性类型为 Map 时,只要当 Map 的键为 String 类型时,依然可以进行正常的注入,比如假设当 @Autowire 所作用的属性类型为 Map<String,Entity>,此时 Map 的键为 BeanName,值为 Entity 类型的 Bean 。

除了上面所述的 @Autowired 的几种应用点,还需要注意的是 @Autowired 中的 required 属性(类似于 @Required 注解),这个属性意味着当前 Bean 注入是否必须成功,当这个 required 为 true 意味着当 Spring 查找不到合适的 Bean 时就要抛出异常,而当 required 为 false 时以为着当前注入非必须,即如果查找不到合适的 Bean 来注入就直接跳过此次注入,不会抛出异常(这种情况下如果非必需方法的依赖项(或者多个参数的依赖项之一)不可用,则根本不会调用该方法)。

最后,我们还可以将 @Autowired 用于众所周知的可解析依赖关系的接口:BeanFactory、ApplicationContext、Environment、ResourceLoader、ApplicationEventPublisher 和 MessageSource。这些接口及其扩展接口(如ConfigurableApplicationContext 或 ResourcePatternResolver)将自动解析,无需特殊设置。

2.2 AutowiredAnnotationBeanPostProcessor

BeanPostProcessor implementation that autowires annotated fields, setter methods and arbitrary config methods. Such members to be injected are detected through a Java 5 annotation: by default, Spring's @Autowired and @Value annotations.

Also supports JSR-330's @Inject annotation, if available, as a direct alternative to Spring's own @Autowired.

首先  AutowiredAnnotationBeanPostProcessor 是 BeanPostProcessor 的一个实现类,它的主要功能是对带注解的方法、set 方法和任意配置方法进行自动注入,而这些要注入的成员是通过 Java 5 注解被检测到的,默认情况下这些注解包括 Spring 的 @Autowired 和 @Value 注解。如果可以的话,还支持 JSR-330 的 @Inject 注解,它们的功能是基本相同的,可以使用 @Inject 直接替代 Spring 自己的 @Autowired,并且不管是 @Inject 还是 @Autowired 注解都是基于 AutowiredAnnotationBeanPostProcessor 实现的。

与之类似的还有 @Resource 注解,它是 JSR-250 中的实现,它与上面的两个类似但不相同,主要是因为它的底层是依赖另一个 CommonAnnotationBeanPostProcessor 来实现的(当然这个 BeanPostProcessor 也在我们将要分析的列表中),同时 @Resource 的默认实现是 autowired by field name,当其失败时才会退化为 autowired by type,而 @Autowired 和 @Inject 的默认实现都是 autowired by type

Only one constructor (at max) of any given bean class may carry this annotation with the 'required' parameter set to true, indicating the constructor to autowire when used as a Spring bean. If multiple non-required constructors carry the annotation, they will be considered as candidates for autowiring. The constructor with the greatest number of dependencies that can be satisfied by matching beans in the Spring container will be chosen. If none of the candidates can be satisfied, then a default constructor (if present) will be used. An annotated constructor does not have to be public.

Fields are injected right after construction of a bean, before any config methods are invoked. Such a config field does not have to be public.

任何给定 Bean 中只有一个构造函数(最多一个)时可以携带这个注释,并应将 required 参数设置为 true,这表明在将构造函数用作 Spring Bean 时,它将自动装配。如果多个非必需构造函数携带注释,那么它们将被视为自动装配的候选构造函数。Spring 将会选择容器中匹配 Bean 且满足最多依赖关系的构造函数。如果没有一个候选项满足,那么将使用缺省构造函数(如果存在),且带注解的构造函数不必是 public

属性在创建 Bean 之后立即注入,然后才会调用配置方法,因此这样的配置属性不必是 public 的

Config methods may have an arbitrary name and any number of arguments; each of those arguments will be autowired with a matching bean in the Spring container. Bean property setter methods are effectively just a special case of such a general config method. Config methods do not have to be public.

 配置方法可以有任意的名称和任意数量的参数,这些参数中的每一个都将由 Spring 容器中匹配的 Bean 自动生成。Bean 属性设置方法实际上只是这种通用配置方法的一个特例,且配置方法不必是 public 的

Note: A default AutowiredAnnotationBeanPostProcessor will be registered by the "context:annotation-config" and "context:component-scan" XML tags. Remove or turn off the default annotation configuration there if you intend to specify a custom AutowiredAnnotationBeanPostProcessor bean definition.

Annotation injection will be performed before XML injection; thus the latter configuration will override the former for properties wired through both approaches.

注意:默认的 AutowiredAnnotationBeanPostProcessor 将由 context:annotation-config 和 context:component-scan XML 标记注册,如果打算指定自定义 AutowiredAnnotationBeanPostProcessor 的 BeanDefinition,请删除或关闭其中的默认注释配置。 

注释注入将在 xml 注入之前执行,因此,对于通过两种方法注入的属性,后一种配置将覆盖前一种配置

In addition to regular injection points as discussed above, this post-processor also handles Spring's @Lookup annotation which identifies lookup methods to be replaced by the container at runtime. This is essentially a type-safe version of getBean(Class, args) and getBean(String, args). 

最后,除了上面讨论的常规注入点之外,这个后置处理器还会处理 Spring 的 @Lookup 注解,该注解标识在运行时需要被容器替换的查找方法,这本质上是 getBean(Class,args)和 getBean(String,args)的类型安全版本。这里可以简单介绍一下 @Lookup 注解,它的作用就是为了解决当相互依赖的两个 Bean 作用范围或者说生命周期不同时的注入问题(主要是针对当在一个单例 Bean 中注入原型 Bean 时,单例 Bean 没有办法总获取到最新的原型 Bean 实例的情况)。

三、源码解析

对于 AutowiredAnnotationBeanPostProcessor 的代码调用主要集中在实例化和初始化 Bean 的过程中,因为在之前的博文中已经多次分析过 Bean 的实例化和初始化流程和相关的代码调用了,因此在这篇博文中就不再赘述,直接从 doCreateBean 方法开始进行梳理(对于这个方法的调用链可以查阅前面的博文)。首先,我们需要对 Spring 当中对 AutowiredAnnotationBeanPostProcessor 的方法调用有一个大概印象。

通过我自己对源码的梳理发现 AutowiredAnnotationBeanPostProcessor 的调用逻辑主要集中在 doCreateBean 方法中(还有一部分集中在 Spring MVC 中,这里就先不分析了),并且主要分为三个部分,第一个部分是在实例化 Bean 的时候在 createBeanInstance 方法中会调用 AutowiredAnnotationBeanPostProcessor 中的方法来获取需要自动注入的构造方法,第二部分是在调用所有 MergedBeanDefinitionPostProcessor 时会调用到 AutowiredAnnotationBeanPostProcessor 的方法来完成对所有需要自动注入的属性和方法的解析和缓存,最后一部分就是在 populatedBean 方法中调用到 AutowiredAnnotationBeanPostProcessor 中的方法来完成需要自动注入属性的注入工作。

最后,为了便于大家理解,对于这上述三部分调用点的代码我已经贴在了下方,下面开始正式的源码解析。

	protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)
			throws BeanCreationException {
                ...
		if (instanceWrapper == null) {
		        // 1.处理自动注入构造方法
			instanceWrapper = createBeanInstance(beanName, mbd, args);
		}
		...
		synchronized (mbd.postProcessingLock) {
			if (!mbd.postProcessed) {
				try {
                                        // 2.扫描注解并缓存注入信息
					applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
				}
			}
		}
                ...
		Object exposedObject = bean;
		try {
                        // 3.完成属性注入
			populateBean(beanName, mbd, instanceWrapper);
			exposedObject = initializeBean(beanName, exposedObject, mbd);
		}
                ...
		return exposedObject;
	}

3.0 示例代码 

@Component
public class BeanA {

	@Autowired
	private BeanB beanB; // 属性自动注入
	private BeanC beanC; // 构造方法自动注入
	private BeanD beanD; // 方法自动注入

	@Autowired
	public BeanA (BeanC beanC){
		this.beanC = beanC;
	}

	@Autowired
	public void setBeanD (BeanD beanD){
		this.beanD = beanD;
	}
}

3.1 处理自动注入的构造方法

protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) {
	...
	// 自动装配的候选构造函数
	Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);
	if (ctors != null || mbd.getResolvedAutowireMode() == AUTOWIRE_CONSTRUCTOR ||
			mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args)) {
		return autowireConstructor(beanName, mbd, ctors, args);
	}

	// 获取默认构造的首选构造函数
	ctors = mbd.getPreferredConstructors();
	if (ctors != null) {
		return autowireConstructor(beanName, mbd, ctors, null);
	}

	// 不需要特殊处理则只需使用无参构造函数。
	return instantiateBean(beanName, mbd);
}

protected Constructor<?>[] determineConstructorsFromBeanPostProcessors(@Nullable Class<?> beanClass, String beanName) throws BeansException {

	if (beanClass != null && hasInstantiationAwareBeanPostProcessors()) {
		for (BeanPostProcessor bp : getBeanPostProcessors()) {
			if (bp instanceof SmartInstantiationAwareBeanPostProcessor) {
                                // 当 bp 为 AutowiredAnnotationBeanPostProcessor 时首先进行强转
				SmartInstantiationAwareBeanPostProcessor ibp = (SmartInstantiationAwareBeanPostProcessor) bp;
                                // 然后调用其 determineCandidateConstructors 方法获取候选构造方法
				Constructor<?>[] ctors = ibp.determineCandidateConstructors(beanClass, beanName);
				if (ctors != null) {
					return ctors;
				}
			}
		}
	}
	return null;
}

 第一部分主要是 AutowiredAnnotationBeanPostProcessor 对于构造方法自动注入的处理,这部分代码的入口就是 createBeanInstance 当中的 determineConstructorsFromBeanPostProcessors 方法,这个方法会通过不同的 BeanPostProcessor 来获取 Bean 不同种类的构造方法。而在这个方法中主要的逻辑就是首先获取到所有的 BeanPostProcessor,然后依次来判断处理,当获取到的 bp 为我们研究的 AutowiredAnnotationBeanPostProcessor 时,会先对其进行类型强转,然后调用它的 determineCandidateConstructors 方法来获取可选的构造方法(这里提示一下,determineCandidateConstructors 的代码逻辑非常非常非常的复杂)。

public Constructor<?>[] determineCandidateConstructors(Class<?> beanClass, final String beanName) throws BeanCreationException {

	// 查找带 @Lookup 注解的方法首先判断 lookupMethodsChecked 集合中是否存在缓存
	if (!this.lookupMethodsChecked.contains(beanName)) {
		try {
                        // 使用反射工具类反射获取类中的方法
			ReflectionUtils.doWithMethods(beanClass, method -> {
                                // 获取 @Lookup 注解信息
				Lookup lookup = method.getAnnotation(Lookup.class);
                                // 如果 @Lookup 注解信息不为空
				if (lookup != null) {
					Assert.state(this.beanFactory != null, "No BeanFactory available");
                                        // 获取 @Lookup 注解所标记的方法的重写方法
					LookupOverride override = new LookupOverride(method, lookup.value());
					try {
                                                // 获取当前 Bean 的 BeanDefinition
						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);
		}
                // 将该 BeanName 添加到已检 Lookup 方法集合中(不管其包不包含 @Lookup 注解)
		this.lookupMethodsChecked.add(beanName);
	}

	// 首先尝试从候选构造方法缓存中获取当前类的候选构造方法
	Constructor<?>[] candidateConstructors = this.candidateConstructorsCache.get(beanClass);
        // 如果缓存中不存在当前类的候选构造方法缓存
	if (candidateConstructors == null) {
		// 使用锁来同步下列操作
		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 语言特性),如果非 Kotlin 则方法直接返回 null
				Constructor<?> primaryConstructor = BeanUtils.findPrimaryConstructor(beanClass);
				int nonSyntheticConstructors = 0;
                                // 遍历所有声明的原生构造方法
				for (Constructor<?> candidate : rawCandidates) {
                                        // 判断是否存在内部类访问(isSynthetic 这个是个很冷门的知识点)
					if (!candidate.isSynthetic()) {
						nonSyntheticConstructors++;
					}
                                        // 对于一般的 Java 类 primaryConstructor 都为 null
					else if (primaryConstructor != null) {
						continue;
					}
                                        // 获取自动注入注解信息
					AnnotationAttributes ann = findAutowiredAnnotation(candidate);
					if (ann == null) {
                                                // 获取用户类
						Class<?> userClass = ClassUtils.getUserClass(beanClass);
                                                // 如果用户类不等于给定类说明使用了 CGLIB 动态代理(此类为生成的代理类)
						if (userClass != beanClass) {
							try {
                                                                // 获取给定类的父类构造方法
								Constructor<?> superCtor = userClass.getDeclaredConstructor(candidate.getParameterTypes());
                                                                // 获取父类的自动注入注解信息
								ann = findAutowiredAnnotation(superCtor);
							}
							catch (NoSuchMethodException ex) {
								// Simply proceed, no equivalent superclass constructor found...
							}
						}
					}
					if (ann != null) {
                                                // 如果必须自动注入的构造方法不为空直接抛异常
						if (requiredConstructor != null) {
							throw new BeanCreationException(beanName,
										"Invalid autowire-marked constructor: " + candidate +
										". Found constructor with 'required' Autowired annotation already: " +
										requiredConstructor);
						}
                                                // 获取注解中 required 的属性值
						boolean required = determineRequiredStatus(ann);
                                                // 如果必须自动注入
						if (required) {
                                                        // 此时 candidates 不为空则抛异常表示已经存在必须自动注入的构造方法了
							if (!candidates.isEmpty()) {
								throw new BeanCreationException(beanName,
											"Invalid autowire-marked constructors: " + candidates +
											". Found constructor with 'required' Autowired annotation: " +
											candidate);
							}
                                                        // 将当前构造函数设置为必须自动注入构造函数
							requiredConstructor = candidate;
						}
                                                // 将当前构造方法添加到候 candidates 集合中
						candidates.add(candidate);
					}
                                        // 如果构造方法为无参构造方法则设置为默认构造方法
					else if (candidate.getParameterCount() == 0) {
						defaultConstructor = candidate;
					}
				}
                                // —————————————————— 到这里 for 循环结束 ——————————————————
                                // 如果可选构造函数集合 candidates 不为空
				if (!candidates.isEmpty()) {
                                        // 且当前不存在必须自动注入的构造函数
					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]);
				}
                                // 如果原生的构造方法只有一个并且为有参方法则将其添加到可选集合中
				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];
				}
                                // 放入缓存集合中
				this.candidateConstructorsCache.put(beanClass, candidateConstructors);
			}
		}
	}
        // 如果获取到了构造方法集合则返回构造方法集合,否则返回 null
	return (candidateConstructors.length > 0 ? candidateConstructors : null);
}

这个 determineCandidateConstructors 方法是 AutowiredAnnotationBeanPostProcessor 的一个核心方法,主要的作用就是获取可选的构造方法,而这个方法的代码非常非常的多,逻辑也是非常非常的复杂,所以可能需要耐下心来一点点的分析,这里我们就从头来梳理一下这个方法。

(1)首先第一部分的逻辑是对于 @Lookup 注解的处理(这点在方法的注解上面也提到过),具体的处理逻辑就是先验证已经检验过 @Lookup 注解的方法集合(lookupMethodsChecked)中是否包含当前方法,如果不包含则通过反射工具的 doWithMethods 方法来反射获取当前类的所有方法,然后对每一个方法调用第二参数的那个 Lambda 表达式进行处理;

(2)表达式中的逻辑即首先获取类中关于 @Lookup 注解的信息(当不包含 @Lookup 注解时为空),如果成功获取到注解信息则证明存在 @Lookup 注解,然后创建一个 LookupOverride 重写方法对象(就是将原 Class 信息和 Method 信息包装为一个新的重写方法对象)对原方法进行封装,之后再获取当前 Bean 所对应的 BeanDefinition 并将刚刚创建的 LookupOverride 重写方法对象添加到 BeanDefinition 中(因为 BeanDefinition 记录着一个 Bean 的相关信息,修改了 BeanDefinition 就意味着修改了将要实例化的 Bean,在这里具体就是为将要实例化的 Bean 添加了一个重写方法),最终处理完毕后将该 BeanName 添加到已检查集合中(lookupMethodsChecked);

(3)接下来进入到对可选构造方法的处理逻辑,首先是尝试从缓存池(candidateConstructorsCache)中获取当前 Bean 所对应的可选构造方法信息,如果获取成功则直接返回;

(4)如果未获取到,则进入到处理逻辑中,首先是获取类中已经声明的所有构造方法,然后依次对它们进行处理;

(5)对于构造方法的处理首先是判断 isSynthetic,这个判断的话是关于内部类的一个判断,比较冷门,在这里的作用也不是特别大,所以就不详细分析,感兴趣的话可以自己去搜索一下,进行完这个判断后又会去判断它是否是一个主类(这个概念是属于 kotlin 里面的,对于 Java 的话上面的获取方法一般都是返回 null),这个判断一般情况下都不会进,所以也不用重点考虑;

(6)接下来或通过 findAutowiredAnnotation 方法(这个方法下面会详细分析)去获取当前类的 @Autowired 、@Value 和 @Inject 注解信息(因为这里这三种注解的功能是相同的,因此这三种注解主要查找到一个就可以返回);

(7)如果最后没有获取到注解信息,那么就进入到第一个逻辑语句块中,先通过工具类的 getUserClass 方法(该方法返回给定类的用户定义类:通常只是给定类,但对于CGLIB生成的子类,则返回原始类)来获取当前类的用户类,然后判断当前的给定类和用户类是否相同,如果不相同则证明当前的类为 CGLIB 代理类(子类),所以去获取它父类中声明的构造方法,并通过 findAutowiredAnnotation 方法再尝试去获取其父类中声明的构造方法的注解信息(@Autowired 、@Value 和 @Inject);

(8)如果最后获取到了注解信息,那么首先判断当前是否已经存在必须自动注入的构造方法(requiredConstructor 是否为空),如果存在则直接抛出异常,如果不存在则通过 determineRequiredStatus 方法获取注解中 required 的属性值,如果当前 required 属性值为 true,表示当前构造方法为必须自动注入方法,如果此时构造方法集合 candidates 中已经存在了构造方法元素,那么直接抛异常,如果不存在的话则将当前构造方法设置为必须自动注入方法(requiredConstructor)并添加到 candidates 集合中。如果当前注解中的 required 属性值为 false,那么直接添加到 candidates 集合中即可。

对于这步逻辑需要我们仔细推敲一下,它的理解需要结合着官方文档,正如下面的官方文档中所描述的,对于 @Autowired 应用于构造方法时,如果 required 值为 true,那么此时只能有一个带有 @Autowired 注解的构造方法,多一个都不行(抛异常)。反之,如果 required 值为 false,那么可以存在多个具有 @Autowired 注解的构造方法,这时它们都会被当做可选构造方法,Spring 会选择参数匹配度最高的那个构造方法来执行构造,但是如果没有找到一个合适的构造方法并且不存在主构造方法和默认构造方法,那么就会抛异常。

Only one constructor of any given bean class may declare @Autowired with the required attribute set to true, indicating the constructor to autowire when used as a Spring bean. Furthermore, if the required attribute is set to true, only a single constructor may be annotated with @Autowired. If multiple non-required constructors declare the annotation, they will be considered as candidates for autowiring. The constructor with the greatest number of dependencies that can be satisfied by matching beans in the Spring container will be chosen. If none of the candidates can be satisfied, then a primary/default constructor (if present) will be used. If a class only declares a single constructor to begin with, it will always be used, even if not annotated. An annotated constructor does not have to be public.

(9)如果当前方法为无参方法则将其设置为默认构造方法;

(10)当循环处理过所有的构造方法之后,如果当前构造方法集合为空,并且不存在必须自动注入的构造方法,并且存在默认构造方法,那么就将默认构造方法添加到可选构造方法集合中;

(11) 如果原生的构造方法只有一个并且为有参方法则将其添加到可选构造方法集合中;

(12)如果原生构造方法存在两个,且存在主构造方法,也存在默认构造方法并且主构造方法不等于默认构造方法则将两个构造方法同时添加到可选构造方法集合中;

(13)如果存在一个构造方法存在访问内部类并且当前存在主类则将主类添加到可选构造方法集合中;

(14)如果全不匹配则直接创建空集合;

(15)最后以类名为键将刚刚处理好的可选构造方法集合 candidateConstructors 中的元素存储到 candidateConstructorsCache 缓存池中,并当缓存池不为空时将其返回,否则返回 null ,至此这个方法分析完毕;

3.2 扫描注解并缓存注入信息

在前面我们已经分析了对于 AutowiredAnnotationBeanPostProcessor 的第一次调用,其主要完成了扫描并处理自动注入的构造方法,当我们完成了自动注入构造方法的处理后会再次返回到 doCreateBean 方法中,在这个方法中会通过调用 applyMergedBeanDefinitionPostProcessors 方法来完成扫描和缓存需要自动注入的属性和方法的工作。

protected void applyMergedBeanDefinitionPostProcessors(RootBeanDefinition mbd, Class<?> beanType, String beanName) {
	for (BeanPostProcessor bp : getBeanPostProcessors()) {
		if (bp instanceof MergedBeanDefinitionPostProcessor) {
			MergedBeanDefinitionPostProcessor bdp = (MergedBeanDefinitionPostProcessor) bp;
			bdp.postProcessMergedBeanDefinition(mbd, beanType, beanName);
		}
	}
}

 对于 applyMergedBeanDefinitionPostProcessors 的代码逻辑比较简单,即首先获取所有的 BeanPostProcessor(这里泛指 BeanPostProcessor 接口实现类的对象),然后再判断其是否为 MergedBeanDefinitionPostProcessor 接口的实现类对象,如果是的话就将其强转类型后调用它的 postProcessMergedBeanDefinition 方法,从这里开始就再次进入到了 AutowiredAnnotationBeanPostProcessor 的代码中。

public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) {
        // 获取自动注入的元数据
	InjectionMetadata metadata = findAutowiringMetadata(beanName, beanType, null);
        // 检查配置成员
	metadata.checkConfigMembers(beanDefinition);
}

private InjectionMetadata findAutowiringMetadata(String beanName, Class<?> clazz, @Nullable PropertyValues pvs) {
	// 返回类名作为缓存键,以便与自定义调用程序向后兼容
	String cacheKey = (StringUtils.hasLength(beanName) ? beanName : clazz.getName());
	// 首先快速检查并发映射集合,力求最小限度的使用锁
	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);
				}
                                // 调用 buildAutowiringMetadata 来构建自动注入元数据
				metadata = buildAutowiringMetadata(clazz);
                                // 将新构建的自动注入元数据放入缓存中
				this.injectionMetadataCache.put(cacheKey, metadata);
			}
		}
	}
        //返回获取到的注入元数据
	return metadata;
}

public static boolean needsRefresh(@Nullable InjectionMetadata metadata, Class<?> clazz) {    
        // 如果注入元数据为空或者注入元数据的目标类不是当前类则返回需要更新(true)
	return (metadata == null || metadata.targetClass != clazz);
}

 postProcessMergedBeanDefinition 进行了两个方法的调用,这里相对来说比较重要的第一个 findAutowiringMetadata 方法的调用,postProcessMergedBeanDefinition 通过这个方法调用完成了自动注入元数据的获取工作,而 findAutowiringMetadata 具体的代码逻辑也比较简单。

(1)获取类名作为元数据缓存集合的键,然后首先通过 get 方法来从缓存集合中获取当前类所对应的元数据,这步的获取以及下一步的检查都是为了尽可能以最小的限度来使用锁,因为如果当前类所对应的元数据不存在,那么接下来的一系列创建添加操作会锁住资源;

(2)当从并发集合中获取到当前类所对应的元数据后,调用 needsRefresh 进行判断,判断的两个条件分别是刚刚获取到的元数据是否为空,如果不为空那么该元数据所对应的目标类是否为当前类,也就是如果刚刚从集合中没有获取到元数据,或者获取到的元数据出现错误,那么我们都需要进行更新;

(3)上面判断需要更新后即开始锁住资源,然后会再进行一次相同的判断,这部分的原理主要是类似于双重检测单例,即这样实现的目的还是为了保证线程的安全,因为当两个线程同时执行到第一个 needsRefresh 且同时返回 true 后都会进入到 if 语句块中,之后一个线程 A 会先拿到锁,另一个线程 B 被阻塞,然后线程 A 拿到锁之后开始进行创建和添加操作,当其完成添加后释放锁,这时线程 B 进入到同步语句块中,如果此时没有第二重的判断,会导致线程 B 再次执行无意义的相同操作。

还有一个问题就是,通过定义我们可以发现 injectionMetadataCache 本身就是一个并发安全的集合(ConcurrentHashMap),那对于它的添加操作本身就是线程安全的,为什么还需要使用 Synchronize 锁来进行同步呢?这里我认为主要是因为虽然对于集合的操作时线程安全的,但是这一系列的操作是非原子的,这一点主要表现在它会调用 buildAutowiringMetadata 方法来创建元数据。因此为了保证创建元数据并成功添加元数据这一系列的操作成功,所以需要进行同步来保证原子性;

(4)当第二重判断决定需要刷新时,会首先判断刚刚获取到的元数据是否为空,如果不为空就证明它所对应的目标类出现了错误(needsRefresh 第二个判断条件),因此需要将它清除;

(5)然后调用 buildAutowiringMetadata 创建元数据,将其添加到 injectionMetadataCache 缓存池中,最后将元数据返回即可;

private InjectionMetadata buildAutowiringMetadata(final Class<?> clazz) {
	List<InjectionMetadata.InjectedElement> elements = new ArrayList<>();
	Class<?> targetClass = clazz;

	do {
		final List<InjectionMetadata.InjectedElement> currElements = new ArrayList<>();
        
                // 使用反射工具类获取属性并调用 Lambda 表达式
		ReflectionUtils.doWithLocalFields(targetClass, field -> {
                    // 解析获取 @Autowired、@Value 和 @Inject 注解信息
			AnnotationAttributes 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;
				}
                                // 获取注解中的 required 属性(是否必须自动注入)
				boolean required = determineRequiredStatus(ann);
                                // 使用属性信息和 required 信息创建 AutowiredFieldElement 对象
                                // 并将其添加到 currElements 集合中
				currElements.add(new AutowiredFieldElement(field, required));
			}
		});

                // 使用反射工具类获取方法并调用 Lambda 表达式
		ReflectionUtils.doWithLocalMethods(targetClass, method -> {
                        // 解析获取方法获取桥接方法
			Method bridgedMethod = BridgeMethodResolver.findBridgedMethod(method);
                        // 如果桥接方法不可见则直接返回
			if (!BridgeMethodResolver.isVisibilityBridgeMethodPair(method, bridgedMethod)) {
				return;
			}
                        // 解析获取 @Autowired、@Value 和 @Inject 注解信息
			AnnotationAttributes 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);
					}
				}
                                // 获取注解中的 required 属性(是否必须自动注入)
				boolean required = determineRequiredStatus(ann);
                                // 为方法获取入参
				PropertyDescriptor pd = BeanUtils.findPropertyForMethod(bridgedMethod, clazz);
                                // 使用方法信息、required 信息创建以及入参信息创建 AutowiredFieldElement 对象并将其添加到 currElements 集合中
				currElements.add(new AutowiredMethodElement(method, required, pd));
			}
		});

		elements.addAll(0, currElements);
                // 获取父类
		targetClass = targetClass.getSuperclass();
	}
        // 如果存在父类且不为 Object 基类则循环进行处理
	while (targetClass != null && targetClass != Object.class);
    
        // 将获取到的需要自动注入的属性和方法连同类信息封装到 InjectionMetadata 对象中返回
	return new InjectionMetadata(clazz, elements);
}

通过上面对 findAutowiringMetadata 方法的分析我们知道在 findAutowiringMetadata 方法中首先会尝试从缓存中获取元数据信息,当其获取失败时就会调用 buildAutowiringMetadata 方法来创建元数据,而在 buildAutowiringMetadata 方法中对于元数据的构建主要包括两个部分,一个是对于自动注入属性的处理,另一部分是对于自动注入方法的处理,因此我们接下来就来分析一下其代码的逻辑。

(1)首先会调用反射工具类的 doWithLocalFields 方法(方法具体实现在下面)来反射获取类中的属性信息,然后对所有的属性依次调用 FieldCallback 的 doWith 方法(也就是我们在 buildAutowiringMetadata 方法中传入的 Lambda 表达式);

(2)然后会对单个属性调用 Lambda 表达式中的代码逻辑,首先通过 findAutowiredAnnotation 来获取到当前属性注解中的关于 @Autowired 、@Value 和 @Inject 信息;

(3)当刚刚获取到的属性的注解信息不为空时,进入下面的逻辑后先判断当前属性是否为静态属性,如果为静态属性在打印 log 日志后直接返回;

(4)之后在通过 determineRequiredStatus 方法(方法具体实现在下面)来解析注解中 required 属性所对应的值(主要是用于判断当前属性是否必须自动注入);

(5)最后将属性信息和其对应的 required 属性值包装为 AutowiredFieldElement 对象后添加到单轮循环的临时集合 currElements 中,然后进入到自动注入方法处理的代码逻辑中;

(6)对于自动注入方法的处理流程类似于属性处理,首先调用反射工具类的  doWithLocalMethods 方法(方法具体实现在下面)来反射获取当前类的方法信息,并对所有获取到的方法调用 MethodCallback 的 doWith 方法来进行处理;

(7)因为传入的 MethodCallback 为一个 Lambda 表达式,因此执行表达式中的代码逻辑,首先先通过 findBridgedMethod 方法来获取桥接方法(桥接方法是 JDK 1.5 引入泛型后,为了使 Java 的泛型方法生成的字节码和 JDK 1.5 前的字节码相兼容,由编译器自动生成的方法),这里一般返回的就是原方法;

(8)然后判断桥接方法是否可见(这里的可见性是指比较桥接方法和桥接方法的函数签名,如果方法的参数和返回类型都相同,那么它就是一个可见的桥接方法),如果不可见则直接返回;

(9)然后通过调用 findAutowiredAnnotation 方法来获取到当前方法注解中的关于 @Autowired 、@Value 和 @Inject 信息;

(10)如果获取注解信息失败,或者不存在相关的注解,或者当前解析的方法和类信息不匹配,那么就跳过这个方法的处理;

(11)如果满足前面的判断,则再判断当前方法是否为静态方法或者无参方法,如果当前方法为静态方法即打印日志后返回;

(12)之后在通过 determineRequiredStatus 方法来解析注解中 required 属性所对应的值(主要是用于判断当前方法是否必须自动注入,如果为必须自动注入则当搜索不到合适的 Bean 来注入时就会抛出异常);

(13)通过 findPropertyForMethod 方法查找合适的 JavaBeans 作为入参(为后面的方法自动注入做准备);

(14)最后将方法信息、其对应的 required 属性值以及搜索到的适合注入的 Bean 参数信息包装为 AutowiredMethodElement 对象后添加到单轮循环的临时集合 currElements 中,然后进入到自动注入方法处理的代码逻辑中;

(15)将临时集合 currElements 中的元素全部添加到 elements 集合中,并获取当前类的父类;

(16)当当前类存在父类,且父类不为 Object 基类时进行循环处理父类;

(17)当前类及父类的属性和方法全部处理完成后将类信息 和 elements 集合封装到 InjectionMetadata 对象中返回;

protected boolean determineRequiredStatus(AnnotationAttributes ann) {
        // this.requiredParameterValue == true
	return (!ann.containsKey(this.requiredParameterName) ||
		this.requiredParameterValue == ann.getBoolean(this.requiredParameterName));
}

public static void doWithLocalFields(Class<?> clazz, FieldCallback fc) {
	for (Field field : getDeclaredFields(clazz)) {
		try {
			fc.doWith(field);
		}
		catch (IllegalAccessException ex) {
			throw new IllegalStateException("Not allowed to access field '" + field.getName() + "': " + ex);
		}
	}
}

public static void doWithLocalMethods(Class<?> clazz, MethodCallback mc) {
	Method[] methods = getDeclaredMethods(clazz);
	for (Method method : methods) {
		try {
			mc.doWith(method);
		}
		catch (IllegalAccessException ex) {
			throw new IllegalStateException("Not allowed to access method '" + method.getName() + "': " + ex);
		}
	}
}
private AnnotationAttributes findAutowiredAnnotation(AccessibleObject ao) {
        // 判断当前是否存在注解信息
	if (ao.getAnnotations().length > 0) {  // autowiring annotations have to be local
                // 一次判断是否存在 @Autowired @Value @Inject 注解,存在即返回
		for (Class<? extends Annotation> type : this.autowiredAnnotationTypes) {
			AnnotationAttributes attributes = AnnotatedElementUtils.getMergedAnnotationAttributes(ao, type);
			if (attributes != null) {
				return attributes;
			}
		}
	}
	return null;
}

 findAutowiredAnnotation 方法主要作用就是判断当前属性或者方法是否包含 @Autowired 、@Value 或者 @Inject 注解,如果存在就直接返回注解信息,因为这三个注解在作用上是相似的,所以只要发现一个就可以终止循环返回了,如果三个注解都没有发现则返回 null 。对于 autowiredAnnotationTypes 集合中的信息我也贴在上面了,就是我们刚刚提到的三个注解,这三个元素是在初始化的时候被放入的类似于常量,所以不用过多考虑相关的逻辑。

3.3 完成属性注入

protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
	...
	boolean hasInstAwareBpps = hasInstantiationAwareBeanPostProcessors();
	boolean needsDepCheck = (mbd.getDependencyCheck() != AbstractBeanDefinition.DEPENDENCY_CHECK_NONE);

	PropertyDescriptor[] filteredPds = null;
	if (hasInstAwareBpps) {
		if (pvs == null) {
			pvs = mbd.getPropertyValues();
		}
		for (BeanPostProcessor bp : getBeanPostProcessors()) {
			if (bp instanceof InstantiationAwareBeanPostProcessor) {
                                // 当 bp 为 AutowiredAnnotationBeanPostProcessor 时先将其进行强转
				InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
                                // 调用其 postProcessProperties 方法
				PropertyValues pvsToUse = ibp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName);
				...
			}
		}
	}
	...
}

public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) {
        // 通过 findAutowiringMetadata 方法获取类所对应的注入元数据
	InjectionMetadata metadata = findAutowiringMetadata(beanName, bean.getClass(), pvs);
	try {
                // 调用 InjectionMetadata 方法进行属性注入
		metadata.inject(bean, beanName, pvs);
	}
	catch (BeanCreationException ex) {
		throw ex;
	}
	catch (Throwable ex) {
		throw new BeanCreationException(beanName, "Injection of autowired dependencies failed", ex);
	}
	return pvs;
}

	private InjectionMetadata findAutowiringMetadata(String beanName, Class<?> clazz, @Nullable PropertyValues pvs) {
		String cacheKey = (StringUtils.hasLength(beanName) ? beanName : clazz.getName());
		InjectionMetadata metadata = this.injectionMetadataCache.get(cacheKey);
		if (InjectionMetadata.needsRefresh(metadata, clazz)) {
			...
		}
		return metadata;
	}

最后一个部分就是对需要自动注入的属性进行属性的自动注入操作,这部分的代码主要集中在 populatedBean 中,在这个方法中会在获取到 AutowiredAnnotationBeanPostProcessor 之后将其进行类型强转,然后调用它的 postProcessProperties 方法,而在这个 postProcessProperties 法中又一次的调用了 findAutowiringMetadata 方法来获取元注解,但是这次与第二次的调用的意义不同。

为了便于理解我把 findAutowiringMetadata 方法的代码又贴了过来,因为我们刚刚在上一步的过程中已经完成了对需要自动注入的属性和方法的元数据缓存工作,也就是说现在缓存池 injectionMetadataCache 的状态应该是如图一图二为此时 Bean 实例的状态,即属性自动注入方法自动注入都还未进行,而构造方法自动注入已经完成),因此这时我们再通过 get 方法是可以获取到 Bean 所对应的元数据的,所以我们判断出当前的元数据不需要刷新,然后直接将获取到的元数据返回,最后在 postProcessProperties 方法中通过该元数据的 inject 方法完成了属性的注入(图三)。

四、内容总结

这篇博文主要是对 @Autowired 注解功能、使用方法的原理,以及 AutowiredAnnotationBeanPostProcessor 类的功能原理和源码进行了比较详细的分析(就说这么多吧,实在太累了,每次分析完一部分源码感觉就被扒了一层皮)。

从没有白费的努力,也没有碰巧的成功。只要认真对待生活,终有一天,你的每一份努力,都将绚烂成花。

发布了244 篇原创文章 · 获赞 32 · 访问量 3万+

猜你喜欢

转载自blog.csdn.net/qq_40697071/article/details/101671956