欢迎大家关注 [github.com/hsfxuebao][github.com_hsfxuebao] ,希望对大家有所帮助,要是觉得可以的话麻烦给点一下Star哈
5. createBeanInstance:bean的创建
createBeanInstance 根据方法名就知道,是创建bean的实例,也就注定了这个方法的不平凡。下面就来一步一步的剖析他。
整个方法的源码如下:
protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) {
// Make sure bean class is actually resolved at this point.
// 解析bean,获取class
Class<?> beanClass = resolveBeanClass(mbd, beanName);
// beanClass != null && 当前类不是public && 不允许访问非公共构造函数和方法。抛出异常
if (beanClass != null && !Modifier.isPublic(beanClass.getModifiers()) && !mbd.isNonPublicAccessAllowed()) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Bean class isn't public, and non-public access not allowed: " + beanClass.getName());
}
// 定义bean实例的提供者
// 1. 是否有bean的 Supplier 接口,如果有,通过回调来创建bean
Supplier<?> instanceSupplier = mbd.getInstanceSupplier();
if (instanceSupplier != null) {
return obtainFromSupplier(instanceSupplier, beanName);
}
// 2. 如果工厂方法不为空,则使用工厂方法初始化策略
// 通过 @Bean 注解方法注入的bean 或者xml 配置注入 的BeanDefinition 会存在这个值。而注入这个bean的方法就是工厂方法。后面会详细解读
// @Bean等可能会调用此方法进行创建出来
if (mbd.getFactoryMethodName() != null) {
// 执行工厂方法,创建bean
return instantiateUsingFactoryMethod(beanName, mbd, args);
}
// Shortcut when re-creating the same bean...
// 3. 尝试使用构造函数构建bean,后面详解
// 经过上面两步,Spring确定没有其他方式来创建bean,所以打算使用构造函数来进行创建bean。 但是 bean 的构造函数可能有多个,需要确定使用哪一个。
// 这里实际上是一个缓存,resolved 表示构造函数是否已经解析完成;autowireNecessary 表示是否需要自动装配
boolean resolved = false;
boolean autowireNecessary = false;
if (args == null) {
synchronized (mbd.constructorArgumentLock) {
// 一个类可能有多个不同的构造函数,每个构造函数参数列表不同,所以调用前需要根据参数锁定对应的构造函数或工程方法
// 如果这个bean的构造函数或者工厂方法已经解析过了,会保存到 mbd.resolvedConstructorOrFactoryMethod 中。这里来判断是否已经解析过了。
if (mbd.resolvedConstructorOrFactoryMethod != null) {
resolved = true;
autowireNecessary = mbd.constructorArgumentsResolved;
}
}
}
// 如果已经解析过则使用功能解析好的构造函数方法,不需要再次解析。
// 这里的是通过 mbd.resolvedConstructorOrFactoryMethod 属性来缓存解析过的构造函数。
if (resolved) {
if (autowireNecessary) {
// 4. 构造函数自动注入
return autowireConstructor(beanName, mbd, null, null);
}
else {
// 5. 使用默认构造函数构造
return instantiateBean(beanName, mbd);
}
}
// Candidate constructors for autowiring?
// 6. 根据参数解析构造函数,并将解析出来的构造函数缓存到mdb 的 resolvedConstructorOrFactoryMethod 属性中
// 到这一步,说明 bean 是第一次加载,所以没有对构造函数进行相关缓存(resolved 为 false)
// 调用 determineConstructorsFromBeanPostProcessors 方法来获取指定的构造函数列表。
// todo 候选的构造器 SmartInstantiationAwareBeanPostProcessor.determineCandidateConstructors()
// 后置处理器有机会在这个决定当前bean使用哪个构造器
Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);
if (ctors != null || mbd.getResolvedAutowireMode() == AUTOWIRE_CONSTRUCTOR ||
mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args)) {
// 构造器的方式自动注入与对象创建
return autowireConstructor(beanName, mbd, ctors, args);
}
// Preferred constructors for default construction?
// 使用默认的自己设置的高优先级的构造器
ctors = mbd.getPreferredConstructors();
if (ctors != null) {
// 构造函数自动注入
return autowireConstructor(beanName, mbd, ctors, null);
}
// No special handling: simply use no-arg constructor.
// 默认使用无参构造器为当前组件创建对象
return instantiateBean(beanName, mbd);
}
步骤如下:
- 如果
RootBeanDefinition
中存在 Supplier 供应商接口,则使用 Supplier 的回调来创建bean。 Supplier是用来替代声明式指定的工厂。 - 如果RootBeanDefinition 中存在 factoryMethodName 属性,或者在配置文件中配置了factory-method,Spring会尝试使用 instantiateUsingFactoryMethod 方法,根据RootBeanDefinition 中的配置生成bean实例。需要注意的是,如果一个类中中的方法被 @Bean注解修饰,那么Spring则会将其封装成一个 ConfigurationClassBeanDefinition。此时 factoryMethodName 也被赋值。所以也会调用instantiateUsingFactoryMethod 方法通过反射完成方法的调用,并将结果注入Spring容器中。
- 当以上两种都没有配置时,Spring则打算通过bean的构造函数来创建bean。首先会判断是否有缓存,即构造函数是否已经被解析过了, 因为一个bean可能会存在多个构造函数,这时候Spring会根据参数列表的来判断使用哪个构造函数进行实例化。但是判断过程比较消耗性能,所以Spring将判断好的构造函数缓存到RootBeanDefinition 中的 resolvedConstructorOrFactoryMethod 属性中。
- 如果存在缓存,则不需要再次解析筛选构造函数,直接调用 autowireConstructor 或者 instantiateBean 方法创建bean。有参构造调用 autowireConstructor 方法,无参构造调用 instantiateBean 方法。
- 如果不存在缓存则需要进行解析,这里通过 determineConstructorsFromBeanPostProcessors 方法调用了 SmartInstantiationAwareBeanPostProcessor.determineCandidateConstructors 的后处理器方法来进行解析,Spring 默认的实现在AutowiredAnnotationBeanPostProcessor.determineCandidateConstructors 方法中。通过determineCandidateConstructors 方法获取到了候选的构造函数(因为满足条件的构造函数可能不止一个,需要进行进一步的选择)。
- 获取解析后的候选的构造函数列表 ctors 后(最终的构造函数就从这个列表中选取),开始调用 autowireConstructor 或者 instantiateBean 方法创建bean。在autowireConstructor 中,进行了候选构造函数的选举,选择最合适的构造函数来构建bean,如果缓存已解析的构造函数,则不用选举,直接使用解析好的构造来进行bean的创建。
执行流程图
需要注意的是,本文分析顺序由于是从代码编写的顺序分析,所以跟实际执行时候的顺序可能并不完全一致。正常的代码流程在第一遍创建bean 时是没有缓存存在的,所以bean在第一遍创建时的执行顺序是 1->2->3->6,当存在缓存的时候则会执行 1->2->3->4->5。需要区别两种执行逻辑。这里建议阅读顺序是 1->2->3->6->4->5
![202301012010359181.png][]
下面我们来分段解析代码。
5.1 调用 Supplier 接口 - obtainFromSupplier
这部分的功能 : 若 RootBeanDefinition 中设置了 Supplier 则使用 Supplier 提供的bean替代Spring要生成的bean
Supplier<?> instanceSupplier = mbd.getInstanceSupplier();
if (instanceSupplier != null) {
return obtainFromSupplier(instanceSupplier, beanName);
}
...
protected BeanWrapper obtainFromSupplier(Supplier<?> instanceSupplier, String beanName) {
Object instance;
// 这里做了一个类似
String outerBean = this.currentlyCreatedBean.get();
this.currentlyCreatedBean.set(beanName);
try {
// 从 Supplier 接口中获取 bean实例
instance = instanceSupplier.get();
}
finally {
if (outerBean != null) {
this.currentlyCreatedBean.set(outerBean);
}
else {
this.currentlyCreatedBean.remove();
}
}
if (instance == null) {
instance = new NullBean();
}
// 包装成 BeanWrapper
BeanWrapper bw = new BeanWrapperImpl(instance);
initBeanWrapper(bw);
return bw;
}
关于其应用场景 : 指定一个用于创建bean实例的回调,以替代声明式指定的工厂方法。主要是考虑反射调用目标方法不如直接调用目标方法效率高。
详参 : [blog.csdn.net/duxd185120/…][blog.csdn.net_duxd185120]
5.2. 使用 factory-method 属性 - instantiateUsingFactoryMethod
如果RootBeanDefinition 中存在 factoryMethodName 属性,或者在配置文件中配置了factory-method,Spring会尝试使用 instantiateUsingFactoryMethod 方法,根据RootBeanDefinition 中的配置生成bean实例。简单来说,就是如果BeanDefinition 指定了工厂方法,则使用其指定的工厂方法来初始化bean
if (mbd.getFactoryMethodName() != null) {
return instantiateUsingFactoryMethod(beanName, mbd, args);
}
这个源码太长,也并不重要,就不在这里展示了。简单来说,这里可以分为两种情况 :
- 在 xml配置中,可以使用
factory-bean
和factory-method
两个标签可以指定一个类中的方法,Spring会将这个指定的方法的返回值作为bean返回(如果方法是静态方法,则可以不创建factorybean就直接调用,否则需要先将factorybean注入到Spring中)。 - 对@Bean 注解的解析。在 ConfigurationClassPostProcessor 后处理器中,会对被 @Bean 注解修饰的方法进行解析,生成一个 ConfigurationClassBeanDefinition的 BeanDefinition。此时BeanDefinition 的 factoryMethodName 正是 @Bean修饰的方法本身。所以这里会调用 instantiateUsingFactoryMethod 方法。通过回调的方式调用 @Bean修饰的方法。并将返回结果注入到Spring容器中。
5.3 构造函数的缓存判断
到达这一步,Spring则打算通过bean的构造函数来创建bean。但是一个bean可能会存在多个构造函数,这时候Spring会根据参数列表的来判断使用哪个构造函数进行实例化。但是判断过程比较消耗性能,所以Spring将判断好的构造函数缓存到RootBeanDefinition
中,如果不存在缓存则进行构造函数的筛选并缓存解析结果。RootBeanDefinition
中具体的缓存属性有如下几个:
RootBeanDefinition 中主要使用如下几个属性缓存 :
resolvedConstructorOrFactoryMethod
: 用于缓存已解析的构造函数或工厂方法constructorArgumentsResolved
:这个字段有两层含义: 一,标记构造函数是否已经完成解析。二,标志这个bean的加载是否 需要通过构造注入(autowireConstructor) 的方式加载。因为只有在autowireConstructor
方法中才会将其置为 true。resolvedConstructorArguments
: 缓存解析好的构造函数的入参
下面我们来看详细代码:
// 是否已经完成解析
boolean resolved = false;
// 标志构造函数参数是否解析完成
boolean autowireNecessary = false;
if (args == null) {
synchronized (mbd.constructorArgumentLock) {
if (mbd.resolvedConstructorOrFactoryMethod != null) {
resolved = true;
autowireNecessary = mbd.constructorArgumentsResolved;
}
}
}
if (resolved) {
if (autowireNecessary) {
// 需要自动注入
return autowireConstructor(beanName, mbd, null, null);
}
else {
// 使用其默认构造函数实例化给定的bean。
return instantiateBean(beanName, mbd);
}
}
// 如果 resolved = false 则会执行第六步
5.4 带有参数的构造函数实例化 - autowireConstructor
上面的代码我们可以看到,Bean的的创建,分为有参构造函数和无参构造函数两种方式进行创建,对于有参构造函数,使用的就是该方法进行处理。这个代码量非常巨大,实现的功能实现上比较复杂,功能上却可以一句话讲清,简单来说,就是根据传入的参数列表,来匹配到合适的构造函数进行bean 的创建。
autowireConstructor(beanName, mbd, null, null);
autowireConstructor 的代码比较复杂,详细代码如下:
// chosenCtors : 候选构造函数列表, 没有则为null
// explicitArgs : 通过getBean方法以编程方式传递的参数值,
public BeanWrapper autowireConstructor(String beanName, RootBeanDefinition mbd,
@Nullable Constructor<?>[] chosenCtors, @Nullable Object[] explicitArgs) {
BeanWrapperImpl bw = new BeanWrapperImpl();
this.beanFactory.initBeanWrapper(bw);
// 候选的构造函数列表
Constructor<?> constructorToUse = null;
ArgumentsHolder argsHolderToUse = null;
// 构造函数最后确定使用的参数
Object[] argsToUse = null;
// 1. 解析构造函数参数
// explicitArgs 参数是通过 getBean 方法传入
// 如果 getBean在调用时传入了参数,那么直接使用即可。getBean 调用的传参,不用从缓存中获取构造函数,需要进行筛选匹配(个人理解,getBean 方法的入参可能并不相同,缓存的构造函数可能并不适用)
if (explicitArgs != null) {
argsToUse = explicitArgs;
}
else {
// 否则 尝试从 BeanDefinition 中加载缓存的bean构造时需要的参数
Object[] argsToResolve = null;
// 加锁
synchronized (mbd.constructorArgumentLock) {
// 从缓存中获取要使用的构造函数。没有缓存则为null
constructorToUse = (Constructor<?>) mbd.resolvedConstructorOrFactoryMethod;
// 如果构造函数不为空 && 构造函数参数已经解析
if (constructorToUse != null && mbd.constructorArgumentsResolved) {
// Found a cached constructor...
// 从缓存中获取。这里如果不能获取到完全解析好的参数,则获取尚未解析的参数,进行解析后再赋值给 argsToUse
// resolvedConstructorArguments 是完全解析好的构造函数参数
argsToUse = mbd.resolvedConstructorArguments;
if (argsToUse == null) {
// 配置构造函数参数
// preparedConstructorArguments 是尚未完全解析的构造函数参数
argsToResolve = mbd.preparedConstructorArguments;
}
}
}
// 如果缓存中存在 尚未完全解析的参数列表,则进行进一步的解析
if (argsToResolve != null) {
// 解析参数类型,如给定的参数列表为(int,int),这时就会将配置中的("1", "1") 转化为 (1,1)
// 缓存中的值可能是最终值,也可能是原始值,因为不一定需要类型转换
argsToUse = resolvePreparedArguments(beanName, mbd, bw, constructorToUse, argsToResolve, true);
}
}
// 如果构造函数 和 构造函数入参都不为空,则可以直接生成bean。否则的话,需要通过一定的规则进行筛选
if (constructorToUse == null || argsToUse == null) {
// Take specified constructors, if any.
// chosenCtors 是候选的构造函数,如果存在候选的构造函数,则跳过这里,否则通过反射获取bean的构造函数集合
// 2. 获取候选的构造参数列表
Constructor<?>[] candidates = chosenCtors;
if (candidates == null) {
Class<?> beanClass = mbd.getBeanClass();
try {
// 反射获取bean的构造函数集合
candidates = (mbd.isNonPublicAccessAllowed() ?
beanClass.getDeclaredConstructors() : beanClass.getConstructors());
}
catch (Throwable ex) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Resolution of declared constructors on bean Class [" + beanClass.getName() +
"] from ClassLoader [" + beanClass.getClassLoader() + "] failed", ex);
}
}
// 如果构造函数只有一个 && getBean 没有传参 && 构造参数无参
// 满足上述三个条件,则无需继续筛选构造函数,直接使用唯一一个构造函数创建 BeanWrapper 并返回即可。
if (candidates.length == 1 && explicitArgs == null && !mbd.hasConstructorArgumentValues()) {
Constructor<?> uniqueCandidate = candidates[0];
// 确定该构造函数无参
if (uniqueCandidate.getParameterCount() == 0) {
synchronized (mbd.constructorArgumentLock) {
// 将解析结束的信息缓存到 mdb中
// 缓存解析出来的唯一构造函数
mbd.resolvedConstructorOrFactoryMethod = uniqueCandidate;
// 标记构造函数已经完全解析
mbd.constructorArgumentsResolved = true;
// 缓存解析好的构造函数参数。这里是空数组 (Object[] EMPTY_ARGS = new Object[0];)
mbd.resolvedConstructorArguments = EMPTY_ARGS;
}
// 调用 instantiate 方法创建对象实例并保存到 bw中
bw.setBeanInstance(instantiate(beanName, mbd, uniqueCandidate, EMPTY_ARGS));
return bw;
}
}
// Need to resolve the constructor.
// 待选构造函数列表不为null || 需要构造注入,则需要解析。
// mbd.getResolvedAutowireMode() 是针对 xml 注入的
boolean autowiring = (chosenCtors != null ||
mbd.getResolvedAutowireMode() == AutowireCapableBeanFactory.AUTOWIRE_CONSTRUCTOR);
ConstructorArgumentValues resolvedValues = null;
// 3. 解析出来的构造函数的个数
int minNrOfArgs;
// 如果explicitArgs 不为空,直接使用它作为参数,毕竟是传入的参数,没必要再从进一步解析。
if (explicitArgs != null) {
minNrOfArgs = explicitArgs.length;
}
else {
// 获取xml配置文件中的配置的构造函数参数
ConstructorArgumentValues cargs = mbd.getConstructorArgumentValues();
// 用于承载解析后的构造函数参数的值
resolvedValues = new ConstructorArgumentValues();
// 确定解析到的构造函数参数个数并进行类型转换匹配。在下面有详细解读
minNrOfArgs = resolveConstructorArguments(beanName, mbd, bw, cargs, resolvedValues);
}
// 4. 寻找最匹配的构造函数
// 对构造函数列表进行排序: public 构造函数优先参数数量降序,非public构造函数参数数量降序
AutowireUtils.sortConstructors(candidates);
int minTypeDiffWeight = Integer.MAX_VALUE;
Set<Constructor<?>> ambiguousConstructors = null;
LinkedList<UnsatisfiedDependencyException> causes = null;
// 遍历构造函数,寻找合适的构造函数
for (Constructor<?> candidate : candidates) {
// 获取当前构造函数参数个数
int parameterCount = candidate.getParameterCount();
// 如果已经找到选用的构造函数 (argstoUse != null) 或者 需要的构造函数的参数个数 小于 当前构造函数参数个数 则终止
// constructorToUse != null 说明找到了构造函数
// argsToUse != null 说明参数已经赋值
// argsToUse.length > parameterCount
// 即已经找到适配的构造函数(可能不是最终的,但参数数量一定相同), 预选构造函数的参数数量 大于 当前构造函数的数量,可以直接break,因为按照参数数量降序排序,这里如果小于就没有必要继续比较下去
if (constructorToUse != null && argsToUse != null && argsToUse.length > parameterCount) {
// Already found greedy constructor that can be satisfied ->
// do not look any further, there are only less greedy constructors left.
break;
}
if (parameterCount < minNrOfArgs) {
// 参数数量不相等,跳过
continue;
}
// 到这里说明尚未找到构造函数,且目前的构造函数和需要的构造函数参数个数相同,下面要对类型进行比较。
ArgumentsHolder argsHolder;
Class<?>[] paramTypes = candidate.getParameterTypes();
// 如果构造函数存在参数,resolvedValues 是上面解析后的构造函数,有参则根据 值 构造对应参数类型的参数
if (resolvedValues != null) {
try {
// 获取参数名称
// 从 @ConstructorProperties 注解上获取参数名称
String[] paramNames = ConstructorPropertiesChecker.evaluate(candidate, parameterCount);
// 为null则说明没有使用注解
if (paramNames == null) {
// 获取参数名称探索器
ParameterNameDiscoverer pnd = this.beanFactory.getParameterNameDiscoverer();
if (pnd != null) {
// 获取指定的构造函数的参数名称
paramNames = pnd.getParameterNames(candidate);
}
}
// 根据类型和数据类型创建 参数持有者
// 这里会调用 DefaultListableBeanFactory#resolveDependency 方法来解析依赖关系
argsHolder = createArgumentArray(beanName, mbd, resolvedValues, bw, paramTypes, paramNames,
getUserDeclaredConstructor(candidate), autowiring, candidates.length == 1);
}
catch (UnsatisfiedDependencyException ex) {
if (logger.isTraceEnabled()) {
logger.trace("Ignoring constructor [" + candidate + "] of bean '" + beanName + "': " + ex);
}
// Swallow and try next constructor.
if (causes == null) {
causes = new LinkedList<>();
}
causes.add(ex);
continue;
}
}
else {
// 如果构造函数为默认构造函数,没有参数,如果参数不完全一致则跳过
// Explicit arguments given -> arguments length must match exactly.
if (parameterCount != explicitArgs.length) {
continue;
}
// 构造函数没有参数的情况
argsHolder = new ArgumentsHolder(explicitArgs);
}
// 探测是否有不确定性的构造函数存在,例如不同构造函数的参数为父子关系
int typeDiffWeight = (mbd.isLenientConstructorResolution() ?
argsHolder.getTypeDifferenceWeight(paramTypes) : argsHolder.getAssignabilityWeight(paramTypes));
// Choose this constructor if it represents the closest match.
// 如果他是当前最接近匹配则选择作为构造函数,因为可能有多个构造函数都同时满足,比如构造函数参数类型全是 Object,选择最合适的(typeDiffWeight 最小的)作为最终构造函数
if (typeDiffWeight < minTypeDiffWeight) {
// 找到最匹配的构造函数赋值保存
constructorToUse = candidate;
argsHolderToUse = argsHolder;
argsToUse = argsHolder.arguments;
minTypeDiffWeight = typeDiffWeight;
ambiguousConstructors = null;
}
else if (constructorToUse != null && typeDiffWeight == minTypeDiffWeight) {
// 如果 已经找到候选构造函数,且当前这个构造函数也有相同的类似度则保存到 ambiguousConstructors 中。后面用于抛出异常
if (ambiguousConstructors == null) {
ambiguousConstructors = new LinkedHashSet<>();
ambiguousConstructors.add(constructorToUse);
}
ambiguousConstructors.add(candidate);
}
}
// 如果 constructorToUse 构造函数为 null,则查找构造函数失败,抛出异常
if (constructorToUse == null) {
if (causes != null) {
UnsatisfiedDependencyException ex = causes.removeLast();
for (Exception cause : causes) {
this.beanFactory.onSuppressedException(cause);
}
throw ex;
}
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Could not resolve matching constructor " +
"(hint: specify index/type/name arguments for simple parameters to avoid type ambiguities)");
}
// 如果ambiguousConstructors 不为空说明有多个构造函数可适配,并且 如果不允许多个存在,则抛出异常
else if (ambiguousConstructors != null && !mbd.isLenientConstructorResolution()) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Ambiguous constructor matches found in bean '" + beanName + "' " +
"(hint: specify index/type/name arguments for simple parameters to avoid type ambiguities): " +
ambiguousConstructors);
}
// 将解析的构造函数加入缓存
if (explicitArgs == null && argsHolderToUse != null) {
argsHolderToUse.storeCache(mbd, constructorToUse);
}
}
Assert.state(argsToUse != null, "Unresolved constructor arguments");
// 将构建的实例加入BeanWrapper 中
bw.setBeanInstance(instantiate(beanName, mbd, constructorToUse, argsToUse));
return bw;
}
简单理一下上面的逻辑:
- 首先判断
explicitArgs
是否为空,如果不为空,则就直接使用 explicitArgs 作为构造函数的参数。 explicitArgs 所代表的意思是 调用getBean方法是的传参,代码中可以看到,如果 explicitArgs 不为空,那么并未从缓存中获取构造函数(个人猜测 getBean 方法调用参数并不一致,可能缓存并不适用) 如下:
![202301012010365972.png][]
- 如果 explicitArgs 为空,则尝试从之缓存中获取,也即是从 RootBeanDefinition 的resolvedConstructorArguments 属性或 preparedConstructorArguments 属性中获取。resolvedConstructorArguments 代表完全解析好的参数, preparedConstructorArguments 代表尚未完全解析的参数,如果 获取到 preparedConstructorArguments ,则需要在进一步的解析。
- 如果缓存中也没有获取到,则只能自己开始分析来获取候选构造函数列表,关于候选构造函数的信息,在调用该方法时就已经传递了过来,即
Constructor<?>[] chosenCtors,如果 Constructor<?>[] chosenCtors
为null,则通过反射获取候选构造函数列表 candidates - 获取到候选构造函数列表 candidates后,则会优先判断获取到的 candidates 是否只有一个构造函数,如果只要一个,则不需要解析,直接保存相关信息即解析完毕。
- 否则则进行候选构造函数列表candidates的选举,寻找最合适的构造函数,对 candidates 按照 public 构造函数优先参数数量降序,非public构造函数参数数量降序 规则排序,目的是为了后面检索的时候可以更快速判断是否有合适的构造函数。
- 排序结束后 ,开始遍历构造函数,按照 构造函数的参数类型和数量与构造函数一一匹配,寻找差异性最小的构造函数作为最终的构造函数并通过 cglib 或者 反射来 创建bean。
按照功能划分,整个 autowireConstructor 方法可以划分为四步:
- 解析构造函数参数
- 获取候选的构造函数列表
- 解析构造函数参数个数
- 寻找最匹配的构造函数
下面分段解析:
5.4.1 解析构造函数参数
// explicitArgs 参数是通过 getBean 方法传入
// 如果 getBean在调用时传入了参数,那么直接使用即可。
if (explicitArgs != null) {
argsToUse = explicitArgs;
}
else {
// 否则 尝试从配置文件中去加载bean构造时需要的参数
Object[] argsToResolve = null;
// 加锁
synchronized (mbd.constructorArgumentLock) {
// 从缓存中获取要使用的构造函数
constructorToUse = (Constructor<?>) mbd.resolvedConstructorOrFactoryMethod;
if (constructorToUse != null && mbd.constructorArgumentsResolved) {
// Found a cached constructor...
// 从缓存中获取。这里如果不能获取到完全解析好的参数,则获取尚未解析的参数,进行解析后再赋值给 argsToUse
// resolvedConstructorArguments 是完全解析好的构造函数参数
argsToUse = mbd.resolvedConstructorArguments;
if (argsToUse == null) {
// 配置构造函数参数
// preparedConstructorArguments 是尚未完全解析的构造函数参数
argsToResolve = mbd.preparedConstructorArguments;
}
}
}
// 如果缓存中存在 尚未完全解析的参数列表,则进行进一步的解析
if (argsToResolve != null) {
// 解析参数类型,如给定的参数列表为(int,int),这时就会将配置中的("1", "1") 转化为 (1,1)
// 缓存中的值可能是最终值,也可能是原始值
argsToUse = resolvePreparedArguments(beanName, mbd, bw, constructorToUse, argsToResolve, true);
}
}
上面的逻辑还是很清楚的
- 如果有传入参数 explicitArgs,则直接使用 explicitArgs
- 如果没有传入,尝试从缓存中获取
- 如果参数完全解析了,则直接使用,如果没有则调用 resolvePreparedArguments 进行解析
这里解释一下 resolvePreparedArguments 方法的作用。
我们声明的构造函数的可能是这样的
public ConstructorDemoA(Integer name) {
this.name = name;
}
但是我们在配置的时候xml配置文件却是这样的。
<bean id="constructorDemoA" class="com.kingfish.springbootdemo.constructor.ConstructorDemoA">
<constructor-arg index="0" value="666" ></constructor-arg>
</bean>
这时候,Spring就需要有一个过程,从Spring 的 “666” 到 Integer 的 666 的转变,这个方法就是做类型转化的工作。但需要注意调用这个方法的前提条件是 argsToResolve != null。
5.4.2 获取候选的构造函数列表
// chosenCtors 是候选的构造函数,入参中传入不同场景下可能为空,可能不为空。
// 如果存在候选的构造函数,则跳过这里,否则获取bean的构造函数集合
Constructor<?>[] candidates = chosenCtors;
if (candidates == null) {
Class<?> beanClass = mbd.getBeanClass();
try {
// 获取bean的构造函数
candidates = (mbd.isNonPublicAccessAllowed() ?
beanClass.getDeclaredConstructors() : beanClass.getConstructors());
}
catch (Throwable ex) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Resolution of declared constructors on bean Class [" + beanClass.getName() +
"] from ClassLoader [" + beanClass.getClassLoader() + "] failed", ex);
}
}
// 如果构造函数只有一个 & getBean 没有传参 & 构造参数无参
// 满足上述三个条件,则无需继续筛选,直接创建 BeanWrapper 并返回即可。
if (candidates.length == 1 && explicitArgs == null && !mbd.hasConstructorArgumentValues()) {
Constructor<?> uniqueCandidate = candidates[0];
if (uniqueCandidate.getParameterCount() == 0) {
synchronized (mbd.constructorArgumentLock) {
mbd.resolvedConstructorOrFactoryMethod = uniqueCandidate;
mbd.constructorArgumentsResolved = true;
mbd.resolvedConstructorArguments = EMPTY_ARGS;
}
bw.setBeanInstance(instantiate(beanName, mbd, uniqueCandidate, EMPTY_ARGS));
return bw;
}
}
这个逻辑也是比较清楚的 chosenCtors 是传入的构造函数列表
- 外部是否传入了候选构造函数列表( chosenCtors == null)
- 如果没传入(chosenCtors 为null),通过反射获取构造函数列表
- 如果构造函数只有一个 & getBean 没有传参 & 构造参数无参,则直接使用这唯一一个构造函数并返回
这里需要注意点是 传入的 chosenCtors ,在不同的调用场景下可能会传入null,或者 调用 SmartInstantiationAwareBeanPostProcessor.determineCandidateConstructors 方法返回的值。Spring 默认的实现是在 AutowiredAnnotationBeanPostProcessor.determineCandidateConstructors 方法中。
5.4.3 解析构造函数参数个数
// 解析出来的构造函数的个数
int minNrOfArgs;
// 如果explicitArgs 不为空,直接使用它作为参数,毕竟是传入的参数,没必要再从进一步解析。
if (explicitArgs != null) {
minNrOfArgs = explicitArgs.length;
}
else {
// 获取xml配置文件中的配置的构造函数参数
ConstructorArgumentValues cargs = mbd.getConstructorArgumentValues();
// 用于保存解析后的构造函数参数的值,在resolveConstructorArguments中可以看到他的作用,
resolvedValues = new ConstructorArgumentValues();
// 确定最终解析到的构造函数参数个数并进行类型转换
minNrOfArgs = resolveConstructorArguments(beanName, mbd, bw, cargs, resolvedValues);
}
在 Spring 中指定的构造函数会保存在 RootBeanDefinition.constructorArgumentValues 中,类型为 ConstructorArgumentValues,如下。可以看到 ConstructorArgumentValues 分为两部分保存参数。
public class ConstructorArgumentValues {
// 按照顺序声明的参数列表
private final Map<Integer, ValueHolder> indexedArgumentValues = new LinkedHashMap<>();
// 按照类型声明的参数列表
private final List<ValueHolder> genericArgumentValues = new ArrayList<>();
...
}
如下的定义中,
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="constructorDemoA" class="com.kingfish.springbootdemo.constructor.ConstructorDemoA">
<constructor-arg index="0" ref="constructorDemoB"></constructor-arg>
<constructor-arg index="1" value="666" ></constructor-arg>
<constructor-arg value="999" ></constructor-arg>
</bean>
<bean id="constructorDemoB" class="com.kingfish.springbootdemo.constructor.ConstructorDemoB"></bean>
</beans>
constructorDemoB、666就被保存到 indexedArgumentValues 中; 999 就被保存到genericArgumentValues ,如下图所示:
![202301012010373503.png][] 但是需要注意的是: 这里面保存的是ValueHolder 类型,里面保存的也并不是 实际类型,而是未经转换的类型,即constructorDemoB 保存的并不是 ConstructorDemoB类 实例,而是保存了一个 beanName 为 constructorDemoB。这里的 666 保存的也是字符串形式(而实际的构造函数需要的是Integer形式)。总的来说就是 mbd.getConstructorArgumentValues(); 中的构造函数值并不一定是真正可以使用的类型,还需要进行一个解析进行类型的匹配。
而这个解析过程就发生在 resolveConstructorArguments 方法中。如下:
private int resolveConstructorArguments(String beanName, RootBeanDefinition mbd, BeanWrapper bw,
ConstructorArgumentValues cargs, ConstructorArgumentValues resolvedValues) {
// 获取类型转换器
TypeConverter customConverter = this.beanFactory.getCustomTypeConverter();
TypeConverter converter = (customConverter != null ? customConverter : bw);
BeanDefinitionValueResolver valueResolver =
new BeanDefinitionValueResolver(this.beanFactory, beanName, mbd, converter);
// 获取参数个数,这并不一定是最终的参数个数
int minNrOfArgs = cargs.getArgumentCount();
// 遍历 indexedArgumentValues
for (Map.Entry<Integer, ConstructorArgumentValues.ValueHolder> entry : cargs.getIndexedArgumentValues().entrySet()) {
int index = entry.getKey();
if (index < 0) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Invalid constructor argument index: " + index);
}
// 这里注意,如果 <constructor-arg> 的index属性大于 参数实际个数,那么Spring会采用index属性的值
if (index > minNrOfArgs) {
// +1 是因为index 从0开始
minNrOfArgs = index + 1;
}
ConstructorArgumentValues.ValueHolder valueHolder = entry.getValue();
// 如果类型已经解析过,则保存在 resolvedValues 中
if (valueHolder.isConverted()) {
resolvedValues.addIndexedArgumentValue(index, valueHolder);
}
else {
// 否则进行类型解析后再保存到 resolvedValues 中
Object resolvedValue =
valueResolver.resolveValueIfNecessary("constructor argument", valueHolder.getValue());
ConstructorArgumentValues.ValueHolder resolvedValueHolder =
new ConstructorArgumentValues.ValueHolder(resolvedValue, valueHolder.getType(), valueHolder.getName());
resolvedValueHolder.setSource(valueHolder);
resolvedValues.addIndexedArgumentValue(index, resolvedValueHolder);
}
}
// 遍历 genericArgumentValues
for (ConstructorArgumentValues.ValueHolder valueHolder : cargs.getGenericArgumentValues()) {
// 如果已经解析,则保存到resolvedValues 中
if (valueHolder.isConverted()) {
resolvedValues.addGenericArgumentValue(valueHolder);
}
else {
// 否则进行类型解析后再保存到 resolvedValues 中
Object resolvedValue =
valueResolver.resolveValueIfNecessary("constructor argument", valueHolder.getValue());
ConstructorArgumentValues.ValueHolder resolvedValueHolder = new ConstructorArgumentValues.ValueHolder(
resolvedValue, valueHolder.getType(), valueHolder.getName());
resolvedValueHolder.setSource(valueHolder);
resolvedValues.addGenericArgumentValue(resolvedValueHolder);
}
}
// 返回解析后的构造函数参数个数。
return minNrOfArgs;
}
5.4.4 寻找最匹配的构造函数
到这里,我们可以知道 minNrOfArgs 为最终构造函数入参数量;candidates 是供选择的构造函数列表。
代码比较长,上面已经贴出了完整版,这里就简化一下。
...
// 排序构造函数,方便后面检索
AutowireUtils.sortConstructors(candidates);
// 差异度,因为可能不止一个构造函数可以匹配,选择匹配度最接近的。最后选择minTypeDiffWeight 最小的作为最匹配的构造函数
int minTypeDiffWeight = Integer.MAX_VALUE;
Set<Constructor<?>> ambiguousConstructors = null;
LinkedList<UnsatisfiedDependencyException> causes = null;
// 筛选构造函数,根据参数数量,参数类型匹配
for (Constructor<?> candidate : candidates) {
...
if (resolvedValues != null) {
try {
// 获取参数名
String[] paramNames = ConstructorPropertiesChecker.evaluate(candidate, parameterCount);
if (paramNames == null) {
ParameterNameDiscoverer pnd = this.beanFactory.getParameterNameDiscoverer();
if (pnd != null) {
paramNames = pnd.getParameterNames(candidate);
}
}
// 这里会调用 DefaultListableBeanFactory#resolveDependency 方法来解析依赖关系
argsHolder = createArgumentArray(beanName, mbd, resolvedValues, bw, paramTypes, paramNames,
getUserDeclaredConstructor(candidate), autowiring, candidates.length == 1);
}
catch (UnsatisfiedDependencyException ex) {
if (logger.isTraceEnabled()) {
logger.trace("Ignoring constructor [" + candidate + "] of bean '" + beanName + "': " + ex);
}
// Swallow and try next constructor.
if (causes == null) {
causes = new LinkedList<>();
}
causes.add(ex);
continue;
}
}
else {
// Explicit arguments given -> arguments length must match exactly.
if (parameterCount != explicitArgs.length) {
continue;
}
argsHolder = new ArgumentsHolder(explicitArgs);
}
...
if (explicitArgs == null && argsHolderToUse != null) {
// 将解析出来的信息缓存到RootBeanDefinition中
argsHolderToUse.storeCache(mbd, constructorToUse);
}
}
Assert.state(argsToUse != null, "Unresolved constructor arguments");
// 创建bean,并保存
bw.setBeanInstance(instantiate(beanName, mbd, constructorToUse, argsToUse));
这一步的目的就是根据参数数量和参数列表来选择最合适的构造函数,并且调用 instantiate(beanName, mbd, constructorToUse, argsToUse) 方法来创建bean实例。
下面提三点:
- 由于在配置文件中声明bean不仅仅可以使用参数位置索引的方式创建,也支持通过参数名称设定参数值的情况,如下:
<constructor-arg name="constructorDemoB" ref="constructorDemoB"></constructor-arg>
所以这时候,就需要首先确定构造函数中的参数名称。而获取参数名的方式有两种,一种是通过注解直接获取(@ConstructorProperties
注解获取),即上面代码中对应的 ConstructorPropertiesChecker.evaluate(candidate, parameterCount);
,另一种是通过Spring同构的工具类 ParameterNameDiscoverer
,这个在代码中也有使用。 完成这一步的时候,构造函数、参数名称、参数类型、参数值都确定后就可以锁定构造函数以及转换对应的参数类型了。
- instantiate 方法也很简单,根据 beanFactory 中的 bean实例化策略来实例化对象
private Object instantiate(
String beanName, RootBeanDefinition mbd, Constructor<?> constructorToUse, Object[] argsToUse) {
try {
// 获取实例化策略
InstantiationStrategy strategy = this.beanFactory.getInstantiationStrategy();
// 通过策略实例化bean
if (System.getSecurityManager() != null) {
return AccessController.doPrivileged((PrivilegedAction<Object>) () ->
strategy.instantiate(mbd, beanName, this.beanFactory, constructorToUse, argsToUse),
this.beanFactory.getAccessControlContext());
}
else {
return strategy.instantiate(mbd, beanName, this.beanFactory, constructorToUse, argsToUse);
}
}
catch (Throwable ex) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Bean instantiation via constructor failed", ex);
}
}
注:关于 实例化策略,主要两种 SimpleInstantiationStrategy
和 CglibSubclassingInstantiationStrategy
,简单实例化策略(直接反射) 和 Cglib 动态代理策略(通过cglib 代理),默认第二种。
- 在这里将解析后的内容添加到缓存中的代码如下:
public void storeCache(RootBeanDefinition mbd, Executable constructorOrFactoryMethod) {
synchronized (mbd.constructorArgumentLock) {
// 保存工厂方法
mbd.resolvedConstructorOrFactoryMethod = constructorOrFactoryMethod;
// 设置已经完全解析
mbd.constructorArgumentsResolved = true;
// 如果必须解析,将一些准备解析的参数保存,后面解析
if (this.resolveNecessary) {
mbd.preparedConstructorArguments = this.preparedArguments;
}
else {
mbd.resolvedConstructorArguments = this.arguments;
}
}
}
5.5. 无参构造函数实例化 - instantiateBean
相较于上面的有参构造函数,无参构造函数的解析显的那么简单
protected BeanWrapper instantiateBean(final String beanName, final RootBeanDefinition mbd) {
try {
Object beanInstance;
final BeanFactory parent = this;
// 这里是对安全管理的处理。
if (System.getSecurityManager() != null) {
beanInstance = AccessController.doPrivileged((PrivilegedAction<Object>) () ->
getInstantiationStrategy().instantiate(mbd, beanName, parent),
getAccessControlContext());
}
else {
beanInstance = getInstantiationStrategy().instantiate(mbd, beanName, parent);
}
BeanWrapper bw = new BeanWrapperImpl(beanInstance);
initBeanWrapper(bw);
return bw;
}
catch (Throwable ex) {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Instantiation of bean failed", ex);
}
}
可以看到,最关键的调用代码是在InstantiationStrategy#instantiate(org.springframework.beans.factory.support.RootBeanDefinition, java.lang.String, org.springframework.beans.factory.BeanFactory)
中,其代码如下:
public Object instantiate(RootBeanDefinition bd, @Nullable String beanName, BeanFactory owner) {
// Don't override the class with CGLIB if no overrides.
// 如果当前bean中的方法没有都没有被重写,则直接反射就好了。不需要使用cglib 来进行代理
if (!bd.hasMethodOverrides()) {
Constructor<?> constructorToUse;
synchronized (bd.constructorArgumentLock) {
// 尝试获取已经解析成功缓存的 构造函数
constructorToUse = (Constructor<?>) bd.resolvedConstructorOrFactoryMethod;
if (constructorToUse == null) {
// 没有缓存则自己指定无参构造函数
final Class<?> clazz = bd.getBeanClass();
// 如果是接口直接抛出异常
if (clazz.isInterface()) {
throw new BeanInstantiationException(clazz, "Specified class is an interface");
}
try {
if (System.getSecurityManager() != null) {
constructorToUse = AccessController.doPrivileged(
(PrivilegedExceptionAction<Constructor<?>>) clazz::getDeclaredConstructor);
}
else {
// 返回符合参数类型的构造函数(这里是无参构造函数,所以并没有传递参数)
constructorToUse = clazz.getDeclaredConstructor();
}
// 指定无参构造函数
bd.resolvedConstructorOrFactoryMethod = constructorToUse;
}
catch (Throwable ex) {
throw new BeanInstantiationException(clazz, "No default constructor found", ex);
}
}
}
// 通过反射创建 bean
return BeanUtils.instantiateClass(constructorToUse);
}
else {
// Must generate CGLIB subclass.
// 如果有方法被重写了,则使用cglib 动态代理
return instantiateWithMethodInjection(bd, beanName, owner);
}
}
getDeclaredConstructor(Class<?>... parameterTypes)
: 这种方法会返回制定參数类型的全部构造器,包含public的和非public的,当然也包含private的。getDeclaredConstructors()
: 的返回结果就没有參数类型的过滤了。getConstructor(Class<?>... parameterTypes)
: 这种方法返回的是上面那个方法返回结果的子集。仅仅返回制定參数类型訪问权限是public的构造器。getConstructors()
: 的返回结果相同也没有參数类型的过滤。
这里的逻辑非常简单, 甚至可以用一句话概括 : 是否有方法被覆盖(是否使用replace 或 lookup 进行配置),有则使用cglib动态代理,增强方法,否则直接通过反射创建。这一块判断是否方法被重写,不是为了事务或者aop,因为解析还没到那一步,这里是为了 lookup-method 和 replaced-method
5.6. 构造函数的筛选
在bean第一次创建的时候,并不存在构造缓存,所以会执行下面的代码。也就是说,这里是Bean第一次创建所调用的代码。
// 调用 SmartInstantiationAwareBeanPostProcessor#determineCandidateConstructors 方法来筛选构造函数。
Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);
// 有候选构造函数 || 构造方式为构造注入 || 有构造函数入参 || 用于构造函数或工厂方法调用的显式参数args 不为null
// 则调用 autowireConstructor 方法
if (ctors != null || mbd.getResolvedAutowireMode() == AUTOWIRE_CONSTRUCTOR ||
mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args)) {
return autowireConstructor(beanName, mbd, ctors, args);
}
// Preferred constructors for default construction?
// 如果有 确定用于默认构造的首选构造函数(如果有)。如有必要,构造函数参数将自动装配。
// RootBeanDefinition 的实现是 null 。这里仅在 GenericApplicationContext.ClassDerivedBeanDefinition 中有过解析
ctors = mbd.getPreferredConstructors();
if (ctors != null) {
return autowireConstructor(beanName, mbd, ctors, null);
}
// No special handling: simply use no-arg constructor.
// 使用默认方式进行bean 构造
return instantiateBean(beanName, mbd);
这里可以看到,如果没有进行任何额外的配置的话,会使用默认的方式instantiateBean(beanName, mbd)
创建bean。
我们这里整理一下调用 autowireConstructor
方法的条件(以下条件满足其一即可):
ctors != null : determineConstructorsFromBeanPostProcessors
方法筛选出的候选构造函数不为null。对于默认的Spring来说,实际返回的是 AutowiredAnnotationBeanPostProcessor#determineCandidateConstructors 方法的返回值。而其作用简单来说就是返回被 @Autowired 注解修饰的构造函数(实际要更为复杂,这里可以简单这样理解),如下:
![202301012010379684.png][]
mbd.getResolvedAutowireMode() == AUTOWIRE_CONSTRUCTOR
:这里的配置是通过xml 来配置bean时指定的装配方式,如果指定了构造装配,则调用 autowireConstructor 方法。如下:
![202301012010387915.png][]
-
mbd.hasConstructorArgumentValues()
:这里表示是否给当前bean定义了构造函数入参。通过xml配置bean的时候可以通过<constructor-arg>
标签指定构造函数入参。如下:![202301012010393126.png][]
-
!ObjectUtils.isEmpty(args)
: 在通过getBean方法以编程方式传递的参数值args。如果有,使用其作为bean创建时构造函数的参数。 -
mbd.getPreferredConstructors() != null : RootBeanDefinition
的实现是 null 。这里仅在 GenericApplicationContext.ClassDerivedBeanDefinition 中有过解析。
关于determineConstructorsFromBeanPostProcessors 方法,实际返回的是 AutowiredAnnotationBeanPostProcessor#determineCandidateConstructors 方法的返回值。
5.7 总结
AbstractAutowireCapableBeanFactory#createBeanInstance
方法处于Spring 创建bean 的入口阶段,完成了bean 的初步创建,调用各种扩展接口来尝试完成bean的创建(Supplier、factory-method),失败了则根据传入参数和和构造函数列表来选择合适的构造函数来创建bean。
但是并未完成属性注入、接口特性实现(如 Aware)、标签设置(如inti-method)的设置
。在后续的 AbstractAutowireCapableBeanFactory#populateBean
方法中完成了属性的注入。
需要注意的是,当一个bean第一次被解析时判断调用 autowireConstructor
方法来进行创建的时候,那么后面再次解析该bean仍会通过 autowireConstructor
方法进行解析。因为 autowireConstructor
方法中在添加缓存的时候将 constructorArgumentsResolved
置为true来确保下一次解析时仍调用 autowireConstructor
方法
6. populateBean:bean属性注入
我们这里先整体过一遍代码,后面进行每一步的详细解读。
// bw: bean实例的包装类型,里面有bean的实例
protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
if (bw == null) {
// 没有属性抛出异常
if (mbd.hasPropertyValues()) {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Cannot apply property values to null instance");
}
else {
// Skip property population phase for null instance.
// 跳过属性填充阶段以获取空实例
return;
}
}
// Give any InstantiationAwareBeanPostProcessors the opportunity to modify the
// state of the bean before properties are set. This can be used, for example,
// to support styles of field injection.
// 1. 属性填充判断 : 这里调用了 InstantiationAwareBeanPostProcessor.postProcessAfterInstantiation方法
// 给InstantiationAwareBeanPostProcessor最后一次机会在属性设置前来改变bean
// 属性赋值之前,后置处理器可以提前准备些东西
// @AutoWired 赋值也在这里 AutowiredAnnotationBeanPostProcessor(直接返回true 没有其他的处理),可以中断初始化行为
if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
for (InstantiationAwareBeanPostProcessor bp : getBeanPostProcessorCache().instantiationAware) {
// todo 执行InstantiationAwareBeanPostProcessor.postProcessAfterInstantiation() 方法
// 返回值为是否继续填充bean
if (!bp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {
return;
}
}
} // 以上的后置处理器可以中断下面的初始化行为
PropertyValues pvs = (mbd.hasPropertyValues() ? mbd.getPropertyValues() : null);
int resolvedAutowireMode = mbd.getResolvedAutowireMode();
// 2. 自动装配 :根据名称或类型自动注入
if (resolvedAutowireMode == AUTOWIRE_BY_NAME || resolvedAutowireMode == AUTOWIRE_BY_TYPE) {
MutablePropertyValues newPvs = new MutablePropertyValues(pvs);
// Add property values based on autowire by name if applicable.
if (resolvedAutowireMode == AUTOWIRE_BY_NAME) {
autowireByName(beanName, mbd, bw, newPvs);
}
// Add property values based on autowire by type if applicable.
if (resolvedAutowireMode == AUTOWIRE_BY_TYPE) {
autowireByType(beanName, mbd, bw, newPvs);
}
pvs = newPvs;
}
// 后处理器已经初始化
boolean hasInstAwareBpps = hasInstantiationAwareBeanPostProcessors();
// 需要依赖检查
boolean needsDepCheck = (mbd.getDependencyCheck() != AbstractBeanDefinition.DEPENDENCY_CHECK_NONE);
PropertyDescriptor[] filteredPds = null;
if (hasInstAwareBpps) {
if (pvs == null) {
// xml中property标签指定的
pvs = mbd.getPropertyValues();
}
// 3. 成员变量的注入
// 调用了InstantiationAwareBeanPostProcessor.postProcessProperties 方法 和 postProcessPropertyValues 方法 来进行设值后处理
// 注解版的属性赋值 后置处理器处理属性(真正的自动装配)
for (InstantiationAwareBeanPostProcessor bp : getBeanPostProcessorCache().instantiationAware) {
// todo 执行InstantiationAwareBeanPostProcessor.postProcessProperties() 方法
PropertyValues pvsToUse = bp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName);
if (pvsToUse == null) {
if (filteredPds == null) {
filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
}
// 如果postProcessProperties 返回null,再调用 postProcessPropertyValues这个过时的方法
pvsToUse = bp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
if (pvsToUse == null) {
return;
}
}
pvs = pvsToUse; // 封装了当前bean的所有属性名和值,可以由后置处理器处理得到
}
}
// 如果需要检查
if (needsDepCheck) {
if (filteredPds == null) {
filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
}
// 依赖检查,对应 depends-on 属性,3.0 已弃用
checkDependencies(beanName, mbd, filteredPds, pvs);
}
if (pvs != null) {
// 4. 将属性应用到bean中
// 把以前处理好的PropertyValues 给bean里面设置一下,主要是上面步骤没有给bean里面设置的属性
// xml版 的所有配置会来到这里 给属性赋值
applyPropertyValues(beanName, mbd, bw, pvs);
}
}
从上看下来,整个流程如下:
InstantiationAwareBeanPostProcessor.postProcessAfterInstantiation 方法
,可以决定程序是否继续进行属性填充。只要有一个InstantiationAwareBeanPostProcessor
返回false,都会终止属性填充的过程。- 根据注入类型(name或type),提取依赖的bean,并统一存入到 propertyValues 中。
- 应用
InstantiationAwareBeanPostProcessor.postProcessProperties
和InstantiationAwareBeanPostProcessor.postProcessPropertyValues
方法,对属性获取完毕填充前对属性的再次处理。 - 将所有
propertyValues
中的属性填充至BeanWrapper
中。
在这里方法里按照如下顺序调用了后处理器
InstantiationAwareBeanPostProcessor.postProcessAfterInstantiation
: 是否使用 InstantiationAwareBeanPostProcessor进行属性装配InstantiationAwareBeanPostProcessor.postProcessProperties
: 进行属性装配InstantiationAwareBeanPostProcessor.postProcessPropertyValues
:和 postProcessProperties 功能相同。已过时
6.1 属性填充判断
// 当前bean不是合成的 && 存在 InstantiationAwareBeanPostProcessor 处理器
// !mbd.isSynthetic() 没明白什么场景
if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof InstantiationAwareBeanPostProcessor) {
InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
if (!ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {
return;
}
}
}
}
如下,这里调用了InstantiationAwareBeanPostProcessor #postProcessAfterInstantiation
方法来决定是否继续注入属性。该方法正常返回true。如果返回false 则将取消对此bean调用任何后续的InstantiationAwareBeanPostProcessor
方法。
6.2 自动装配
在下面这段代码中,对 AUTOWIRE_BY_NAME
类型和 AUTOWIRE_BY_TYPE
的 种类进行自动装配。
if (resolvedAutowireMode == AUTOWIRE_BY_NAME || resolvedAutowireMode == AUTOWIRE_BY_TYPE) {
MutablePropertyValues newPvs = new MutablePropertyValues(pvs);
// Add property values based on autowire by name if applicable.
if (resolvedAutowireMode == AUTOWIRE_BY_NAME) {
// 根据 beanName 进行装配
autowireByName(beanName, mbd, bw, newPvs);
}
// Add property values based on autowire by type if applicable.
if (resolvedAutowireMode == AUTOWIRE_BY_TYPE) {
// 根据 bean 类型进行装配
autowireByType(beanName, mbd, bw, newPvs);
}
pvs = newPvs;
}
这一段代码的目的是,如果bean在声明的时候指定了自动注入类型是 byName或者byType,则会根据这个规则,对 bean内部的排除某些特定的属性(排除规则后面详解), 进行byName 或者 byType的自动装配。
6.2.1. 自动装配 - autowireByName
protected void autowireByName(
String beanName, AbstractBeanDefinition mbd, BeanWrapper bw, MutablePropertyValues pvs) {
// 寻找bw中需要依赖注入的属性name
String[] propertyNames = unsatisfiedNonSimpleProperties(mbd, bw);
for (String propertyName : propertyNames) {
// 检查缓存bean 中是否有当前bean
if (containsBean(propertyName)) {
// 递归初始化bean,会调用doGetBean 来 获取bean
Object bean = getBean(propertyName);
pvs.add(propertyName, bean);
// 注册依赖,将依赖关系保存到 Map<String, Set<String>> dependentBeanMapdependentBeanMap 中,key是 bean,value是 转化后的 propertyName
registerDependentBean(propertyName, beanName);
if (logger.isTraceEnabled()) {
logger.trace("Added autowiring by name from bean name '" + beanName +
"' via property '" + propertyName + "' to bean named '" + propertyName + "'");
}
}
else {
// 找不到则不处理
if (logger.isTraceEnabled()) {
logger.trace("Not autowiring property '" + propertyName + "' of bean '" + beanName +
"' by name: no matching bean found");
}
}
}
}
可以看到,byName
的处理逻辑很简单,一句话概括,获取需要注入的bean然后递归调用getBean获取bean进行注入。 关于 unsatisfiedNonSimpleProperties
方法在后面有讲解。
6.2.2. 自动装配 - autowireByType
byType 的装配和 byName 对我们感觉来说似乎没什么差异,但是在实际实现上却截然不同,代码也复杂的多。具体代码如下:
protected void autowireByType(
String beanName, AbstractBeanDefinition mbd, BeanWrapper bw, MutablePropertyValues pvs) {
// 获取自定义的类型转换器
TypeConverter converter = getCustomTypeConverter();
if (converter == null) {
converter = bw;
}
Set<String> autowiredBeanNames = new LinkedHashSet<>(4);
// 寻找 bw中需要依赖注入的属性name
String[] propertyNames = unsatisfiedNonSimpleProperties(mbd, bw);
for (String propertyName : propertyNames) {
try {
// 获取属性描述符
PropertyDescriptor pd = bw.getPropertyDescriptor(propertyName);
// Don't try autowiring by type for type Object: never makes sense,
// even if it technically is a unsatisfied, non-simple property.
// 这里不解析Object的官方注释 :不要尝试按类型为Object类型自动装配:即使从技术上讲是不满意的,非简单的属性,也从没有意义。
if (Object.class != pd.getPropertyType()) {
// 获取指定属性的 set 方法
MethodParameter methodParam = BeanUtils.getWriteMethodParameter(pd);
// Do not allow eager init for type matching in case of a prioritized post-processor.
boolean eager = !(bw.getWrappedInstance() instanceof PriorityOrdered);
DependencyDescriptor desc = new AutowireByTypeDependencyDescriptor(methodParam, eager);
// 解析指定beanName 的属性所匹配的值,并把解析到的属性名存储在 autowiredBeanNames 中
// 当属性存在多个封装bean时,如 @Autowired List<Bean> beans,会找到所有的匹配Bean 类型的bean并将其注入。
// 这里的返回值是真正的需要注入的属性, autowiredBeanNames 是需要注入的属性(可能是集合)的names
Object autowiredArgument = resolveDependency(desc, beanName, autowiredBeanNames, converter);
if (autowiredArgument != null) {
// 添加到待注入的bean列表中
pvs.add(propertyName, autowiredArgument);
}
// 注册依赖
for (String autowiredBeanName : autowiredBeanNames) {
// 注册依赖关系。操作 dependentBeanMap 和 dependenciesForBeanMap 集合
registerDependentBean(autowiredBeanName, beanName);
if (logger.isTraceEnabled()) {
logger.trace("Autowiring by type from bean name '" + beanName + "' via property '" +
propertyName + "' to bean named '" + autowiredBeanName + "'");
}
}
autowiredBeanNames.clear();
}
}
catch (BeansException ex) {
throw new UnsatisfiedDependencyException(mbd.getResourceDescription(), beanName, propertyName, ex);
}
}
下面提两点 :
关于 registerDependentBean
方法,我们在之前的文章中有过解释,请查看上篇文章。
这里面的主要的逻辑被封装到了 resolveDependency 方法中,我们下面来看看DefaultListableBeanFactory#resolveDependency
方法的具体实现。目前我所知另外调用地方:
AutowiredAnnotationBeanPostProcessor
中注入处理@Autowired
注入的时候也调用了该方法ConstructorResolver#autowireConstructor
在resolveAutowiredArgument( methodParam, beanName, autowiredBeanNames, converter, fallback);
时也调用了该方法。
6.2.2.1 DefaultListableBeanFactory#resolveDependency
public Object resolveDependency(DependencyDescriptor descriptor, @Nullable String requestingBeanName,
@Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException {
descriptor.initParameterNameDiscovery(getParameterNameDiscoverer());
// 针对不同类型的不同处理
if (Optional.class == descriptor.getDependencyType()) {
return createOptionalDependency(descriptor, requestingBeanName);
}
else if (ObjectFactory.class == descriptor.getDependencyType() ||
ObjectProvider.class == descriptor.getDependencyType()) {
return new DependencyObjectProvider(descriptor, requestingBeanName);
}
else if (javaxInjectProviderClass == descriptor.getDependencyType()) {
return new Jsr330Factory().createDependencyProvider(descriptor, requestingBeanName);
}
else {
// 处理bean是否懒加载,如果懒加载,创建一个代理对象注入bean
Object result = getAutowireCandidateResolver().getLazyResolutionProxyIfNecessary(
descriptor, requestingBeanName);
if (result == null) {
// 针对一般类型的通用
result = doResolveDependency(descriptor, requestingBeanName, autowiredBeanNames, typeConverter);
}
return result;
}
}
上面的逻辑比较清晰,对一些特殊的类型进行特殊处理,一般的通用处理都会调用 doResolveDependency
方法。这里我们不去关注特殊类型的处理,下面再来看看 DefaultListableBeanFactory#doResolveDependency 方法
,代码如下。
6.2.2.2 DefaultListableBeanFactory#doResolveDependency
@Nullable
public Object doResolveDependency(DependencyDescriptor descriptor, @Nullable String beanName,
@Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException {
// 只有ShortcutDependencyDescriptor实现了resolveShortcut方法,返回了非空值。目前版本代码只在AutowiredFieldElement、AutowiredMethodElement类中使用到,也即是说,只有解析@Autowired、@Value注解的元素才会用到,目的是为了将解析结果缓存起来,避免重复解析
InjectionPoint previousInjectionPoint = ConstructorResolver.setCurrentInjectionPoint(descriptor);
try {
// 尝试获取缓存
Object shortcut = descriptor.resolveShortcut(this);
if (shortcut != null) {
// 存在缓存直接返回
return shortcut;
}
// 获取 依赖的类型
Class<?> type = descriptor.getDependencyType();
// 取值@Value注解中的value属性中的值,这里取出的值是未经修改的值,即带有 ${} 标签的值。如果descriptor未被@Value标注,则返回null
Object value = getAutowireCandidateResolver().getSuggestedValue(descriptor);
if (value != null) {
// 到这里说明属性被 @Value 注解修饰了,这里是解析 @Value 注解的逻辑
// 如果value不为null,
if (value instanceof String) {
// 处理占位符如${},做占位符的替换(不解析SP EL表达式)
String strVal = resolveEmbeddedValue((String) value);
BeanDefinition bd = (beanName != null && containsBean(beanName) ?
getMergedBeanDefinition(beanName) : null);
// 解析SP EL(如#{})
value = evaluateBeanDefinitionString(strVal, bd);
}
TypeConverter converter = (typeConverter != null ? typeConverter : getTypeConverter());
try {
// 类型转换,把解析出来的结果转成type类型
return converter.convertIfNecessary(value, type, descriptor.getTypeDescriptor());
}
catch (UnsupportedOperationException ex) {
// A custom TypeConverter which does not support TypeDescriptor resolution...
return (descriptor.getField() != null ?
converter.convertIfNecessary(value, type, descriptor.getField()) :
converter.convertIfNecessary(value, type, descriptor.getMethodParameter()));
}
}
// 对集合类型进行处理,包括,Array、Collection、Map。后面详解
Object multipleBeans = resolveMultipleBeans(descriptor, beanName, autowiredBeanNames, typeConverter);
if (multipleBeans != null) {
// 如果解析出来集合类型,则直接返回
return multipleBeans;
}
// 调用查找所有类型为type的实例,存放在matchingBeans <beanName, bean> (在 resolveMultipleBeans 方法中也是核心也是调用该方法)。下面详解
Map<String, Object> matchingBeans = findAutowireCandidates(beanName, type, descriptor);
if (matchingBeans.isEmpty()) {
if (isRequired(descriptor)) {
// 如果没有找到,并且bean 并标注为 required = true, 则抛出NoSuchBeanDefinitionException异常
raiseNoMatchingBeanFound(type, descriptor.getResolvableType(), descriptor);
}
return null;
}
String autowiredBeanName;
Object instanceCandidate;
// 如果找到了不止一个匹配的bean,Spring 按照一定规则进行挑选
if (matchingBeans.size() > 1) {
// 按以下顺序,找到符合条件的就直接返回
// 1. 挑选出被标识为primary的bean
// 2. 挑选标识了@Priority,且先级级最高的bean。可以不标识,一旦标识,不允许同一优先级的存在
// 3. fallback,依赖的名称与matchingBeans中任意一Key匹配
autowiredBeanName = determineAutowireCandidate(matchingBeans, descriptor);
if (autowiredBeanName == null) {
if (isRequired(descriptor) || !indicatesMultipleBeans(type)) {
// 非集合类,找到了多个符合条件的Bean,抛出异常
return descriptor.resolveNotUnique(descriptor.getResolvableType(), matchingBeans);
}
else {
// In case of an optional Collection/Map, silently ignore a non-unique case:
// possibly it was meant to be an empty collection of multiple regular beans
// (before 4.3 in particular when we didn't even look for collection beans).
return null;
}
}
instanceCandidate = matchingBeans.get(autowiredBeanName);
}
else {
// We have exactly one match.
// 如果只找到了唯一匹配的元素,则直接使用
Map.Entry<String, Object> entry = matchingBeans.entrySet().iterator().next();
autowiredBeanName = entry.getKey();
instanceCandidate = entry.getValue();
}
if (autowiredBeanNames != null) {
// 将待装配的Bean名称放入autowiredBeanNames集合里
autowiredBeanNames.add(autowiredBeanName);
}
if (instanceCandidate instanceof Class) {
// 这里又去调用 getBean 方法去获取bean
instanceCandidate = descriptor.resolveCandidate(autowiredBeanName, type, this);
}
Object result = instanceCandidate;
if (result instanceof NullBean) {
if (isRequired(descriptor)) {
// 如果 result 是 NullBean类型,且 required = true,则抛出异常
raiseNoMatchingBeanFound(type, descriptor.getResolvableType(), descriptor);
}
result = null;
}
// 类型校验,确保类型与解析出来的Bean实例能够匹配
if (!ClassUtils.isAssignableValue(type, result)) {
throw new BeanNotOfRequiredTypeException(autowiredBeanName, type, instanceCandidate.getClass());
}
return result;
}
finally {
ConstructorResolver.setCurrentInjectionPoint(previousInjectionPoint);
}
}
...
protected String determineAutowireCandidate(Map<String, Object> candidates, DependencyDescriptor descriptor) {
// 获取类型
Class<?> requiredType = descriptor.getDependencyType();
// 获取 primary 的 候选beanName
String primaryCandidate = determinePrimaryCandidate(candidates, requiredType);
if (primaryCandidate != null) {
return primaryCandidate;
}
// 获取 Priority 最高(优先级最高的) beanName
String priorityCandidate = determineHighestPriorityCandidate(candidates, requiredType);
if (priorityCandidate != null) {
return priorityCandidate;
}
// Fallback
// 通过回调返回。
for (Map.Entry<String, Object> entry : candidates.entrySet()) {
String candidateName = entry.getKey();
Object beanInstance = entry.getValue();
if ((beanInstance != null && this.resolvableDependencies.containsValue(beanInstance)) ||
matchesBeanName(candidateName, descriptor.getDependencyName())) {
return candidateName;
}
}
return null;
}
6.2.2.3 DefaultListableBeanFactory#resolveMultipleBeans
这个方法是用来处理 数组、Collection、Map 类型的注入。具体实现如下:
private Object resolveMultipleBeans(DependencyDescriptor descriptor, @Nullable String beanName,
@Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) {
final Class<?> type = descriptor.getDependencyType();
// 如果是 StreamDependencyDescriptor 类型,则返回流的形式
if (descriptor instanceof StreamDependencyDescriptor) {
Map<String, Object> matchingBeans = findAutowireCandidates(beanName, type, descriptor);
if (autowiredBeanNames != null) {
autowiredBeanNames.addAll(matchingBeans.keySet());
}
Stream<Object> stream = matchingBeans.keySet().stream()
.map(name -> descriptor.resolveCandidate(name, type, this))
.filter(bean -> !(bean instanceof NullBean));
if (((StreamDependencyDescriptor) descriptor).isOrdered()) {
stream = stream.sorted(adaptOrderComparator(matchingBeans));
}
return stream;
}
// 如果是 数组类型
else if (type.isArray()) {
// 确定最终类型
Class<?> componentType = type.getComponentType();
ResolvableType resolvableType = descriptor.getResolvableType();
Class<?> resolvedArrayType = resolvableType.resolve(type);
if (resolvedArrayType != type) {
componentType = resolvableType.getComponentType().resolve();
}
if (componentType == null) {
return null;
}
// 根据属性类型找到 beanFactory 中所有类型的匹配bean
// 返回值构成 : key= 匹配的beanName, value= beanName对应的实例化bean,通过 getBean(beanName)获取。
Map<String, Object> matchingBeans = findAutowireCandidates(beanName, componentType,
new MultiElementDescriptor(descriptor));
// 如果是未找到匹配的bean,则返回null,
if (matchingBeans.isEmpty()) {
return null;
}
// 保存所有适配的 beanName
if (autowiredBeanNames != null) {
autowiredBeanNames.addAll(matchingBeans.keySet());
}
// 进行类型转换,将bean 转换为对应的type 类型。
TypeConverter converter = (typeConverter != null ? typeConverter : getTypeConverter());
Object result = converter.convertIfNecessary(matchingBeans.values(), resolvedArrayType);
if (result instanceof Object[]) {
Comparator<Object> comparator = adaptDependencyComparator(matchingBeans);
if (comparator != null) {
// 排序
Arrays.sort((Object[]) result, comparator);
}
}
return result;
}
// 对 Collection 类型的处理,逻辑基本同上,这里不再赘述
else if (Collection.class.isAssignableFrom(type) && type.isInterface()) {
Class<?> elementType = descriptor.getResolvableType().asCollection().resolveGeneric();
if (elementType == null) {
return null;
}
Map<String, Object> matchingBeans = findAutowireCandidates(beanName, elementType,
new MultiElementDescriptor(descriptor));
if (matchingBeans.isEmpty()) {
return null;
}
if (autowiredBeanNames != null) {
autowiredBeanNames.addAll(matchingBeans.keySet());
}
TypeConverter converter = (typeConverter != null ? typeConverter : getTypeConverter());
Object result = converter.convertIfNecessary(matchingBeans.values(), type);
if (result instanceof List) {
if (((List<?>) result).size() > 1) {
Comparator<Object> comparator = adaptDependencyComparator(matchingBeans);
if (comparator != null) {
((List<?>) result).sort(comparator);
}
}
}
return result;
}
// 对map类型的处理,逻辑类似上面
else if (Map.class == type) {
ResolvableType mapType = descriptor.getResolvableType().asMap();
Class<?> keyType = mapType.resolveGeneric(0);
if (String.class != keyType) {
return null;
}
Class<?> valueType = mapType.resolveGeneric(1);
if (valueType == null) {
return null;
}
Map<String, Object> matchingBeans = findAutowireCandidates(beanName, valueType,
new MultiElementDescriptor(descriptor));
if (matchingBeans.isEmpty()) {
return null;
}
if (autowiredBeanNames != null) {
autowiredBeanNames.addAll(matchingBeans.keySet());
}
return matchingBeans;
}
else {
return null;
}
}
可以看到的是,如果是集合类型,内部的核心方法也是 findAutowireCandidates
方法。所以下面还是来看 DefaultListableBeanFactory#findAutowireCandidates
方法。
6.2.2.4.DefaultListableBeanFactory#findAutowireCandidates
protected Map<String, Object> findAutowireCandidates(
@Nullable String beanName, Class<?> requiredType, DependencyDescriptor descriptor) {
// 根据 Class 类型,找到对应的候选beanName,
String[] candidateNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
this, requiredType, true, descriptor.isEager());
Map<String, Object> result = new LinkedHashMap<>(candidateNames.length);
// 这里我们一般不会涉及。如果注入的是 resolvableDependencies key类型,则会装配成value类型
for (Map.Entry<Class<?>, Object> classObjectEntry : this.resolvableDependencies.entrySet()) {
Class<?> autowiringType = classObjectEntry.getKey();
if (autowiringType.isAssignableFrom(requiredType)) {
Object autowiringValue = classObjectEntry.getValue();
autowiringValue = AutowireUtils.resolveAutowiringValue(autowiringValue, requiredType);
if (requiredType.isInstance(autowiringValue)) {
result.put(ObjectUtils.identityToString(autowiringValue), autowiringValue);
break;
}
}
}
// 遍历候选的beanName
for (String candidate : candidateNames) {
// 不是自引用 && 允许被注入(autowire-candidate 标签指定)
if (!isSelfReference(beanName, candidate) && isAutowireCandidate(candidate, descriptor)) {
// 将结果添加到result中
addCandidateEntry(result, candidate, descriptor, requiredType);
}
}
// 如果目前找到的匹配的bean集合为空
if (result.isEmpty()) {
// Array || Collection || Map 。即是否表示多个bean的集合类型
boolean multiple = indicatesMultipleBeans(requiredType);
// Consider fallback matches if the first pass failed to find anything...
DependencyDescriptor fallbackDescriptor = descriptor.forFallbackMatch();
for (String candidate : candidateNames) {
// 非自引用 && 允许被注入 && (非集合类 || 解析 @Qualifier 注解或者 javax.inject.Qualifier类成功)
// 这里开始分析解析的属性是否被 @Qualifier 注解或者 javax.inject.Qualifier类 限定符限定了
if (!isSelfReference(beanName, candidate) && isAutowireCandidate(candidate, fallbackDescriptor) &&
(!multiple || getAutowireCandidateResolver().hasQualifier(descriptor))) {
addCandidateEntry(result, candidate, descriptor, requiredType);
}
}
// 如果还没找到 && 非集合类
if (result.isEmpty() && !multiple) {
// Consider self references as a final pass...
// but in the case of a dependency collection, not the very same bean itself.
for (String candidate : candidateNames) {
// 将自我引用视为最后一步。判断是不是自己引用自己
if (isSelfReference(beanName, candidate) &&
(!(descriptor instanceof MultiElementDescriptor) || !beanName.equals(candidate)) &&
isAutowireCandidate(candidate, fallbackDescriptor)) {
addCandidateEntry(result, candidate, descriptor, requiredType);
}
}
}
}
return result;
}
...
private void addCandidateEntry(Map<String, Object> candidates, String candidateName,
DependencyDescriptor descriptor, Class<?> requiredType) {
// 根据类型判断,如果是MultiElementDescriptor,获取后保存到候选列表中
if (descriptor instanceof MultiElementDescriptor) {
Object beanInstance = descriptor.resolveCandidate(candidateName, requiredType, this);
if (!(beanInstance instanceof NullBean)) {
candidates.put(candidateName, beanInstance);
}
}
// 如果 单例缓存中存在 || 是 StreamDependencyDescriptor 的类型 && order = true
else if (containsSingleton(candidateName) || (descriptor instanceof StreamDependencyDescriptor &&
((StreamDependencyDescriptor) descriptor).isOrdered())) {
// 调用了beanFacotory.getBean 方法获取bean
Object beanInstance = descriptor.resolveCandidate(candidateName, requiredType, this);
// 保存起来
candidates.put(candidateName, (beanInstance instanceof NullBean ? null : beanInstance));
}
else {
// getType 调用了beanFacotory.getBean 方法
candidates.put(candidateName, getType(candidateName));
}
}
这里提两点:
- 这里需要注意
resolvableDependencies
。其在DefaultListableBeanFactory#resolvableDependencies
定义如下,其作用是,当一些其他的类需要装配key类型的bean时,实际装配的类型是key对应的value 类型。
/** Map from dependency type to corresponding autowired value. */
// key 是映射值,value是实际注入值
private final Map<Class<?>, Object> resolvableDependencies = new ConcurrentHashMap<>(16);
在 Spring默认的代码中,仅仅有八个元素保存到其中,如下:
![202301012010404827.png][] 如下, DemoA2021 默认装配的BeanFactory 类型是 DefaultListableBeanFactory 类型:
@Data
public class DemoA2021 {
private DemoB2021 demob;
private DemoC2021 democ;
private List<Demo> demos;
private BeanFactory beanFactory;
}
![202301012010414438.png][] 2. 从上面的代码可以看到,Spring寻找合适的bean的要求是一再放宽的 : 非自引用 -> 被 Qualifier 限定符修饰的bean -> 自引用。
autowire-candidate
:xml中在注入bean 的时候有该属性。@Bean也有对应的属性。其作用是用来标记当前bean是否会被作为注入的候选bean。默认值 true:表示其他bean可以把当前bean作为属性注入。如果false:表示其他bean选在注入属性 bean时将忽略当前bean。这一点在上面的代码中也有体现
6.2.3 排除规则 - unsatisfiedNonSimpleProperties
在autowireByName
和 autowireByType
方法中,都有如下一行代码
String[] propertyNames = unsatisfiedNonSimpleProperties(mbd, bw);
在 unsatisfiedNonSimpleProperties
方法中,对Bean 的属性进行了过滤,得到了需要自动装配的属性。我们来详细看看里面的内容。
protected String[] unsatisfiedNonSimpleProperties(AbstractBeanDefinition mbd, BeanWrapper bw) {
Set<String> result = new TreeSet<>();
// 获取bean 的property 属性
PropertyValues pvs = mbd.getPropertyValues();
// 获取 bw 中的属性描述
PropertyDescriptor[] pds = bw.getPropertyDescriptors();
for (PropertyDescriptor pd : pds) {
// if pd属性具有set方法 && 依赖检查中没有被忽略 && 没有被配置成 property 属性 && 不是简单类型
if (pd.getWriteMethod() != null && !isExcludedFromDependencyCheck(pd) && !pvs.contains(pd.getName()) &&
!BeanUtils.isSimpleProperty(pd.getPropertyType())) {
// 添加到需要装配的集合中
result.add(pd.getName());
}
}
// 返回需要自动装配的bean集合
return StringUtils.toStringArray(result);
}
可以看到过滤条件
- 装配 属性具有set 方法: 因为后面的装配是通过set方法装配
- 依赖检查中没有被忽略
- 没有被property 属性,因为这里property 会被单独处理,不需要在这里保存
- 不是简单类型,即不属于Void、void、 Enum、CharSequence、Number、Date、Temporal、URI、URL、Locale、Class 和 八大基本数据类型及其包装类型。可以看到如下代码,ClassUtils.isPrimitiveOrWrapper(type) 判断是type是否属于基本数据类型或者其包装类型。 *``` public static boolean isSimpleValueType(Class<?> type) { return (Void.class != type && void.class != type && (ClassUtils.isPrimitiveOrWrapper(type) || Enum.class.isAssignableFrom(type) || CharSequence.class.isAssignableFrom(type) || Number.class.isAssignableFrom(type) || Date.class.isAssignableFrom(type) || Temporal.class.isAssignableFrom(type) || URI.class == type || URL.class == type || Locale.class == type || Class.class == type)); }
## 6.3 成员变量的注入 ##
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof InstantiationAwareBeanPostProcessor) {
InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
PropertyValues pvsToUse = ibp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName);
if (pvsToUse == null) {
if (filteredPds == null) {
filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
}
pvsToUse = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
if (pvsToUse == null) {
return;
}
}
pvs = pvsToUse;
}
}
这里通过 `InstantiationAwareBeanPostProcessor` 的 后处理器的`postProcessPropertyValues` 方法完成了属性的注入。Spring 默认是通过 `AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues` 的实现来完成的属性的注入。
@Override
public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) {
//
InjectionMetadata metadata = findAutowiringMetadata(beanName, bean.getClass(), pvs);
try {
// 在这里面又调用了 getBean 方法来获取bean
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;
}
这里不再具体分析 `AutowiredAnnotationBeanPostProcessor` 的实现,详参后面文章 `AutowiredAnnotationBeanPostProcessor` 中完成了`@Autowired、@Value` 注解的自动注入功能。 大概逻辑是,获取被 `@Autowired` 修饰的 属性或者方法,如果是属性,则通过getBean 获取bean并注入,如果是方法,则获取方法参数后,invoke 方法(调用该方法,因为我们一般写的都是set方法,给属性注入赋值)。
## 6.4 applyPropertyValues ##
上面只是将属性保存了起来,并未真正设置到bean中,这里设置到bean中
protected void applyPropertyValues(String beanName, BeanDefinition mbd, BeanWrapper bw, PropertyValues pvs) {
if (pvs.isEmpty()) {
return;
}
if (System.getSecurityManager() != null && bw instanceof BeanWrapperImpl) {
((BeanWrapperImpl) bw).setSecurityContext(getAccessControlContext());
}
MutablePropertyValues mpvs = null;
List<PropertyValue> original;
// 如果pvs 是 MutablePropertyValues 类型的封装
if (pvs instanceof MutablePropertyValues) {
mpvs = (MutablePropertyValues) pvs;
// 如果 mpv 中的值类型已经转换完毕,则可以直接设置到BeanWrapper 中
if (mpvs.isConverted()) {
// Shortcut: use the pre-converted values as-is.
try {
bw.setPropertyValues(mpvs);
return;
}
catch (BeansException ex) {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Error setting property values", ex);
}
}
// 保存原始值,等待类型转换
original = mpvs.getPropertyValueList();
}
else {
// 保存原始值,等待类型转换
original = Arrays.asList(pvs.getPropertyValues());
}
// 获取类型转换器
TypeConverter converter = getCustomTypeConverter();
if (converter == null) {
converter = bw;
}
BeanDefinitionValueResolver valueResolver = new BeanDefinitionValueResolver(this, beanName, mbd, converter);
// Create a deep copy, resolving any references for values.
// 准备进行深拷贝
List<PropertyValue> deepCopy = new ArrayList<>(original.size());
boolean resolveNecessary = false;
// 遍历属性,将属性转换为对应类的对应属性类型
for (PropertyValue pv : original) {
// 如果已经转换之后直接保存
if (pv.isConverted()) {
deepCopy.add(pv);
}
else {
// 进行类型转换
String propertyName = pv.getName();
Object originalValue = pv.getValue();
if (originalValue == AutowiredPropertyMarker.INSTANCE) {
Method writeMethod = bw.getPropertyDescriptor(propertyName).getWriteMethod();
if (writeMethod == null) {
throw new IllegalArgumentException("Autowire marker for property without write method: " + pv);
}
originalValue = new DependencyDescriptor(new MethodParameter(writeMethod, 0), true);
}
Object resolvedValue = valueResolver.resolveValueIfNecessary(pv, originalValue);
Object convertedValue = resolvedValue;
boolean convertible = bw.isWritableProperty(propertyName) &&
!PropertyAccessorUtils.isNestedOrIndexedProperty(propertyName);
if (convertible) {
convertedValue = convertForProperty(resolvedValue, propertyName, bw, converter);
}
// Possibly store converted value in merged bean definition,
// in order to avoid re-conversion for every created bean instance.
if (resolvedValue == originalValue) {
if (convertible) {
pv.setConvertedValue(convertedValue);
}
deepCopy.add(pv);
}
else if (convertible && originalValue instanceof TypedStringValue &&
!((TypedStringValue) originalValue).isDynamic() &&
!(convertedValue instanceof Collection || ObjectUtils.isArray(convertedValue))) {
pv.setConvertedValue(convertedValue);
deepCopy.add(pv);
}
else {
resolveNecessary = true;
deepCopy.add(new PropertyValue(pv, convertedValue));
}
}
}
if (mpvs != null && !resolveNecessary) {
mpvs.setConverted();
}
// Set our (possibly massaged) deep copy.
try {
bw.setPropertyValues(new MutablePropertyValues(deepCopy));
}
catch (BeansException ex) {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Error setting property values", ex);
}
}
## 6.5 关于 自动装配 ##
在上面的代码我们看到 byName 和 byType 的两种自动装配的解析过程。 但实际上并非仅仅这两种自动装配方式。
如下:
| 名称|解释|
| :-----: | :-----: |
| AUTOWIRE_DEFAULT | 默认类型,和AUTOWIRE_NO相同。需要自己通过标签或者ref属性来指定需要注入的bean类型 |
| AUTOWIRE_NO | 和AUTOWIRE_DEFAULT相同 |
| AUTOWIRE_BY_NAME | 按照bean名称注入 |
| AUTOWIRE_BY_TYPE | 按照bean类型注入 |
| AUTOWIRE_AUTODETECT | 已过时 |
如下:
@Data
public class DemoA2021 {
private DemoB2021 demob;
}
...
@Data
public class DemoB2021 {
private DemoC2021 demoC2021;
}
...
public class DemoC2021 {}
在 xml 中的配置。
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
// 因为 demoA2021 指定了 autowire = byType。所以其内部属性(需要有set方法) 会被按照类型检测自动装配
<bean id="demoA2021" name="demoA2021" class="com.kingfish.springbootdemo.component.DemoA2021" autowire="byType"/>
// demoB2021没有指定 autowire。默认是 no,也是 default。就需要自己通过 <property ref> 来指定对应的bean进行注入
<bean id="demoB2021" name="demoB2021" class="com.kingfish.springbootdemo.component.DemoB2021">
<property name="demoC2021" ref="demoC2021"/>
</bean>
<bean id="demoC2021" name="demoC2021" class="com.kingfish.springbootdemo.component.DemoC2021"/>
</beans>
装配方式可以通过`@Bean(autowire = Autowire.BY_NAME)`来指定注入方式。也可以通过xml配置中的`< bean ... autowire="byName">`来指定,`默认是 Autowire.NO`,autowire 指的是当前bean内部引用的属性是以什么方式注入。不过需要注意的是,这个属性已经过时了,Spring并不推荐继续使用。
目前的理解程度:
* `AUTOWIRE_DEFAULT & AUTOWIRE_NO` :没有特殊指定不会处理bean。如果通过 `<property>` 标签指定。则会在AbstractAutowireCapableBeanFactory\#populateBean 方法中完成了解析。
* `AUTOWIRE_AUTODETECT`:在 `AbstractAutowireCapableBeanFactory#createBeanInstance` 中完成了解析。
* `AUTOWIRE_BY_TYPE & AUTOWIRE_BY_NAME` :在`AbstractAutowireCapableBeanFactory#populateBean` 方法中完成了解析。
## 6.6 总结 ##
populateBean 在bean创建结束之后,完成了对 bean属性的注入。根据byName、byType 的不同类型注入有不同的解析方式。
# 7. initializeBean:bean的初始化 #
具体代码如下:
protected Object initializeBean(String beanName, Object bean, @Nullable RootBeanDefinition mbd) {
// 对特殊的bean进行处理 : 实现了 Aware、BeanClassLoaderAware、BeanFactoryAware 的处理。后面详解
if (System.getSecurityManager() != null) {
AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
// 激活 Aware 方法
invokeAwareMethods(beanName, bean);
return null;
}, getAccessControlContext());
}
else {
// todo 组件有Aware接口,先Aware; BeanNameAware BeanClassLoaderAware BeanFactoryAware
invokeAwareMethods(beanName, bean);
}
Object wrappedBean = bean;
if (mbd == null || !mbd.isSynthetic()) {
// 调用了bean后处理器的方法
// todo 执行后置处理器的 BeforeInitialization,可以改变之前创建的bean实例
wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
}
try {
// 激活自定义的init的方法。
// todo 执行初始化方法实现InitializingBean.afterPropertiesSet() 实现InitializingBean 的接口
invokeInitMethods(beanName, wrappedBean, mbd);
}
catch (Throwable ex) {
throw new BeanCreationException(
(mbd != null ? mbd.getResourceDescription() : null),
beanName, "Invocation of init method failed", ex);
}
if (mbd == null || !mbd.isSynthetic()) {
// 调用bean后处理器的方法
// todo 执行后置处理器的 postProcessAfterInitialization
wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
}
return wrappedBean;
}
上面关于两个后处理器的调用,本文就不再赘述了,分别调用了 `BeanPostProcessor. postProcessBeforeInitialization、BeanPostProcessor.postProcessAfterInitialization` 方法。
对后处理器比较感兴趣的可以看之前的文章。
所以我们主要分析下面两个方法 :
## 7.1 invokeAwareMethods - 激活 Aware 方法 ##
这个方法很简单,完成了 Aware 接口的激活功能。可以简单的说 :
* 如果bean实现了`BeanNameAware` 接口,则将 beanName设值进去
* 如果bean实现了`BeanClassLoaderAware`接口,则将 ClassLoader 设值进去
* 如果bean实现了`BeanFactoryAware`接口,则将 beanFactory 设值进去
private void invokeAwareMethods(final String beanName, final Object bean) {
if (bean instanceof Aware) {
if (bean instanceof BeanNameAware) {
((BeanNameAware) bean).setBeanName(beanName);
}
if (bean instanceof BeanClassLoaderAware) {
ClassLoader bcl = getBeanClassLoader();
if (bcl != null) {
((BeanClassLoaderAware) bean).setBeanClassLoader(bcl);
}
}
if (bean instanceof BeanFactoryAware) {
((BeanFactoryAware) bean).setBeanFactory(AbstractAutowireCapableBeanFactory.this);
}
}
}
这里简单解释一下 Aware的作用。从上面的代码可以看到,实现不同类型的 Aware 接口会接受到不同得到初始化数据。
举个例子: 如果bean实现了 BeanFactoryAware 接口,那么他就可以在bean内部获取到beanFacotory。
其实Aware 接口的作用 我在分析 AutowiredAnnotationBeanPostProcessor 后处理器的时候才突然想明白的。 AutowiredAnnotationBeanPostProcessor 中完成了Bean的属性和方法注入,属性要从BeanFactory 的缓存中获取,那么AutowiredAnnotationBeanPostProcessor 如何得到的beanFactory呢? 答案是实现了BeanFactoryAware 接口。这样在 AutowiredAnnotationBeanPostProcessor 初始化的时候就通过 void setBeanFactory(BeanFactory beanFactory) 获取到beanFactory。如下图。AutowiredAnnotationBeanPostProcessor 保存了setBeanFactory 带来的beanFactory,并通过此来从容器中获取需要的bean。
![202301012010422589.png][]
## 7.2 invokeInitMethods - 激活自定义的init方法 ##
首先需要注意的是,Bean 的初始化方法除了可以使用 `init-method` 属性(或者 `@Bean(initMethod=''”))`,还可以通过`实现InitializingBean接口`,并且在`afterPropertiesSet 方法`中实现自己初始化的业务逻辑。
调用顺序则是 `afterPropertiesSet 先调用,后面调用 init-method 指定的方法`。这一点从下面的代码逻辑就能看到。
protected void invokeInitMethods(String beanName, Object bean, @Nullable RootBeanDefinition mbd)
throws Throwable {
// todo 如果组件实现了InitializingBean接口,就调用afterPropertiesSet()
boolean isInitializingBean = (bean instanceof InitializingBean);
if (isInitializingBean && (mbd == null || !mbd.hasAnyExternallyManagedInitMethod("afterPropertiesSet"))) {
if (logger.isTraceEnabled()) {
logger.trace("Invoking afterPropertiesSet() on bean with name '" + beanName + "'");
}
if (System.getSecurityManager() != null) {
try {
AccessController.doPrivileged((PrivilegedExceptionAction<Object>) () -> {
((InitializingBean) bean).afterPropertiesSet();
return null;
}, getAccessControlContext());
}
catch (PrivilegedActionException pae) {
throw pae.getException();
}
}
else {
((InitializingBean) bean).afterPropertiesSet();
}
}
// 自定义的初始化方法
if (mbd != null && bean.getClass() != NullBean.class) {
// 从RootBeanDefinition 中获取initMethod 方法名称
String initMethodName = mbd.getInitMethodName();
if (StringUtils.hasLength(initMethodName) &&
!(isInitializingBean && "afterPropertiesSet".equals(initMethodName)) &&
!mbd.hasAnyExternallyManagedInitMethod(initMethodName)) {
// todo 执行自定义的初始化方法
invokeCustomInitMethod(beanName, bean, mbd);
}
}
}
# 8. bean创建对象及初始化流程图 #
![2023010120104324910.png][]
![2023010120104542211.png][]
# 参考文章 #
[Spring5源码注释github地址][Spring5_github]
Spring源码深度解析(第2版)
[spring源码解析][spring]
[Spring源码深度解析笔记][Spring]
[Spring注解与源码分析][Spring 1]
[Spring注解驱动开发B站教程][Spring_B]
[github.com_hsfxuebao]: https://link.juejin.cn/?target=https%3A%2F%2Fgithub.com%2Fhsfxuebao
[202301012010359181.png]: http://image.skjava.com/article/common/2023/1/202301012010359181.png
[blog.csdn.net_duxd185120]: https://link.juejin.cn?target=https%3A%2F%2Fblog.csdn.net%2Fduxd185120%2Farticle%2Fdetails%2F109224025
[202301012010365972.png]: http://image.skjava.com/article/common/2023/1/202301012010365972.png
[202301012010373503.png]: http://image.skjava.com/article/common/2023/1/202301012010373503.png
[202301012010379684.png]: http://image.skjava.com/article/common/2023/1/202301012010379684.png
[202301012010387915.png]: http://image.skjava.com/article/common/2023/1/202301012010387915.png
[202301012010393126.png]: http://image.skjava.com/article/common/2023/1/202301012010393126.png
[202301012010404827.png]: http://image.skjava.com/article/common/2023/1/202301012010404827.png
[202301012010414438.png]: http://image.skjava.com/article/common/2023/1/202301012010414438.png
[202301012010422589.png]: http://image.skjava.com/article/common/2023/1/202301012010422589.png
[2023010120104324910.png]: http://image.skjava.com/article/common/2023/1/2023010120104324910.png
[2023010120104542211.png]: http://image.skjava.com/article/common/2023/1/2023010120104542211.png
[Spring5_github]: https://link.juejin.cn?target=https%3A%2F%2Fgithub.com%2Fhsfxuebao%2Fspring-framework-5.3.x
[spring]: https://link.juejin.cn?target=https%3A%2F%2Fblog.csdn.net%2Fm0_46690280%2Fcategory_11226727.html
[Spring]: https://link.juejin.cn?target=https%3A%2F%2Fblog.csdn.net%2Fqq_36882793%2Farticle%2Fdetails%2F106440723
[Spring 1]: https://link.juejin.cn?target=https%3A%2F%2Fblog.csdn.net%2Flalalabababa%2Farticle%2Fdetails%2F124040514
[Spring_B]: https://link.juejin.cn?target=https%3A%2F%2Fwww.bilibili.com%2Fvideo%2FBV1gW411W7wy%3Fspm_id_from%3D333.337.search-card.all.click