Spring实例化(createBeanInstance)源码解析
一,createBeanInstance()方法概述
createBeanInstance 是Spring实例化的核心代码,它根据不同的情况会调用四种实例化方法:
- obtainFromSupplier():通过Supplier实例化。
- instantiateUsingFactoryMethod():通过工厂方法实例化。
- autowireConstructor():用合适的构造函数实例化。
- instantiateBean():用无参构造函数实例化。
protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) {
// 确认需要创建的bean实例的类可以实例化
Class<?> beanClass = resolveBeanClass(mbd, beanName);
// 确保class不为空,并且访问权限是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());
}
/**
* ----------1,通过Supplier实例化------------
*/
Supplier<?> instanceSupplier = mbd.getInstanceSupplier();
if (instanceSupplier != null) {
return obtainFromSupplier(instanceSupplier, beanName);
}
/**
* ----------2,通过工厂方法实例化------------
*/
if (mbd.getFactoryMethodName() != null) {
return instantiateUsingFactoryMethod(beanName, mbd, args);
}
/**
* ----------3,用合适的构造函数实例化------------
*
* 一个类可能有多个构造器,所以Spring得根据参数个数、类型确定需要调用的构造器。
* 在使用构造器创建实例后,Spring会将解析过后确定下来的构造器或工厂方法保存在缓存中,
* 避免再次创建相同bean时再次解析
*/
// 标记下,防止重复创建同一个bean
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 {
// 使用默认构造函数构造
return instantiateBean(beanName, mbd);
}
}
// 从bean后置处理器中为自动装配寻找构造方法
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);
}
/**
* ----------4,使用默认构造函数构造------------
*/
return instantiateBean(beanName, mbd);
}
以上源码主要包括:
- 如果RootBeanDefinition中存在Supplier接口实例,则使用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
方法中。 - 获取解析后的候选的构造函数列表 ctors 后(最终的构造函数就从这个列表中选取),开始调用
autowireConstructor
或者instantiateBean
方法创建bean。在autowireConstructor
中,进行了候选构造函数的选举,选择最合适的构造函数来构建bean,如果缓存已解析的构造函数,则不用选举,直接使用解析好的构造来进行bean的创建。
二,obtainFromSupplier()通过Supplier实例化
/**
* 从supplier获取bean
*/
protected BeanWrapper obtainFromSupplier(Supplier<?> instanceSupplier, String beanName) {
Object instance;
// 获取原先创建的beanName
String outerBean = this.currentlyCreatedBean.get();
// 用当前作对做替换
this.currentlyCreatedBean.set(beanName);
try {
// 调用supplier的方法
instance = instanceSupplier.get();
}
finally {
if (outerBean != null) {
this.currentlyCreatedBean.set(outerBean);
}
else {
this.currentlyCreatedBean.remove();
}
}
// 如果没有创建对象,默认为NullBean
if (instance == null) {
instance = new NullBean();
}
// 初始化BeanWrapper并返回
BeanWrapper bw = new BeanWrapperImpl(instance);
initBeanWrapper(bw);
return bw;
}
Supplier方式比较简单,instanceSupplier.get()回调到自己定义的函数里面返回一个实例对象然后包装成BeanWrapperImpl返回就行了。
三,instantiateUsingFactoryMethod()通过工厂方法实例化。
如果RootBeanDefinition
中存在 factoryMethodName
属性,或者在配置文件中配置了factory-method
,Spring会尝试使用 instantiateUsingFactoryMethod
方法,根据RootBeanDefinition 中的配置生成bean实例。
这个源码太长,也并不重要,就不在这里展示了。简单来说,这里可以分为两种情况:
- 在 xml配置中,可以使用
factory-bean
和factory-method
两个标签可以指定一个类中的方法,Spring会将这个指定的方法的返回值作为bean返回(如果方法是静态方法,则可以不创建factory-bean
就直接调用,否则需要先将factory-bean
注入到Spring中)。 - 对
@Bean
注解的解析。在ConfigurationClassPostProcessor
后处理器中,会对被 @Bean 注解修饰的方法进行解析,生成一个ConfigurationClassBeanDefinition
的BeanDefinition
。此时BeanDefinition
的factoryMethodName
正是@Bean
修饰的方法本身。所以这里会调用instantiateUsingFactoryMethod
方法。通过回调的方式调用@Bean
修饰的方法。并将返回结果注入到Spring容器中。
四,autowireConstructor():用合适的构造函数实例化
这个代码量也非常大,实现的功能实现上比较复杂,功能上却可以一句话讲清:简单来说,就是根据传入的参数列表,来匹配到合适的构造函数进行bean 的创建。
public BeanWrapper autowireConstructor(String beanName, RootBeanDefinition mbd,
@Nullable Constructor<?>[] chosenCtors, @Nullable Object[] explicitArgs) {
// 实例化BeanWrapper。是包装bean的容器
BeanWrapperImpl bw = new BeanWrapperImpl();
this.beanFactory.initBeanWrapper(bw);
Constructor<?> constructorToUse = null;
ArgumentsHolder argsHolderToUse = null;
Object[] argsToUse = null;
// explicitArgs通过getBean方法传入
// 如果getBean方法调用的时候指定方法参数那么直接使用
if (explicitArgs != null) {
argsToUse = explicitArgs;
}
else {
// 如果在调用getBean方法的时候没有指定,则尝试从配置文件中解析
Object[] argsToResolve = null;
synchronized (mbd.constructorArgumentLock) {
// 尝试从缓存中获取
constructorToUse = (Constructor<?>) mbd.resolvedConstructorOrFactoryMethod;
if (constructorToUse != null && mbd.constructorArgumentsResolved) {
// Found a cached constructor...
// 从缓存中找到了构造器,那么继续从缓存中寻找缓存的构造器参数
argsToUse = mbd.resolvedConstructorArguments;
if (argsToUse == null) {
// 没有缓存的参数,就需要获取配置i文件中配置的参数
argsToResolve = mbd.preparedConstructorArguments;
}
}
}
// 如果缓存中没有缓存的参数的话,即argsToResolve不为空,就需要解析配置的参数
if (argsToResolve != null) {
// 解析参数类型,比如将配置的String类型转换为list、boolean等类型
argsToUse = resolvePreparedArguments(beanName, mbd, bw, constructorToUse, argsToResolve, true);
}
}
// 如果没有缓存,就需要从构造函数开始解析
if (constructorToUse == null || argsToUse == null) {
// Take specified constructors, if any.
// 如果传入的构造器数组不为空,就使用传入的过后早期参数,否则通过反射获取class中定义的构造器
Constructor<?>[] candidates = chosenCtors;
if (candidates == null) {
Class<?> beanClass = mbd.getBeanClass();
try {
// 使用public的构造器或者所有构造器
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);
}
}
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;
}
}
// Need to resolve the constructor.
boolean autowiring = (chosenCtors != null ||
mbd.getResolvedAutowireMode() == AutowireCapableBeanFactory.AUTOWIRE_CONSTRUCTOR);
ConstructorArgumentValues resolvedValues = null;
int minNrOfArgs;
if (explicitArgs != null) {
minNrOfArgs = explicitArgs.length;
}
else {
// 提取配置文件中的配置的构造函数参数
ConstructorArgumentValues cargs = mbd.getConstructorArgumentValues();
// 用于承载解析后的构造函数参数的值
resolvedValues = new ConstructorArgumentValues();
// 能解析到的参数个数
minNrOfArgs = resolveConstructorArguments(beanName, mbd, bw, cargs, resolvedValues);
}
// 排序给定的构造函数,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();
// 如果已经找到选用的构造函数或者需要的参数个数小于当前的构造函数参数个数则终止,前面已经经过了排序操作
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();
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);
}
}
// 根据名称和数据类型创建参数持有者
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.
// 如果它代表着当前最接近的匹配则选择作为构造函数
if (typeDiffWeight < minTypeDiffWeight) {
constructorToUse = candidate;
argsHolderToUse = argsHolder;
argsToUse = argsHolder.arguments;
minTypeDiffWeight = typeDiffWeight;
ambiguousConstructors = null;
}
else if (constructorToUse != null && typeDiffWeight == minTypeDiffWeight) {
if (ambiguousConstructors == null) {
ambiguousConstructors = new LinkedHashSet<>();
ambiguousConstructors.add(constructorToUse);
}
ambiguousConstructors.add(candidate);
}
}
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)");
}
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
为空,则尝试从缓存中获取,也即是从RootBeanDefinition
的resolvedConstructorArguments
属性或preparedConstructorArguments
属性中获取。resolvedConstructorArguments
代表完全解析好的参数,preparedConstructorArguments
代表尚未完全解析的参数,如果 获取到preparedConstructorArguments
,则需要在进一步的解析。 -
如果缓存中也没有获取到,则只能自己开始分析来获取候选构造函数列表,关于候选构造函数的信息,在调用该方法时就已经传递了过来,即
Constructor<?>[] chosenCtors
,如果Constructor<?>[] chosenCtors
为null,则通过反射获取候选构造函数列表 candidates -
获取到候选构造函数列表
candidates
后,则会优先判断获取到的candidates
是否只有一个构造函数,如果只要一个,则不需要解析,直接保存相关信息即解析完毕。 -
否则则进行候选构造函数列表
candidates
的选举,寻找最合适的构造函数,对candidates
按照 public 构造函数优先参数数量降序,非public构造函数参数数量降序 规则排序,目的是为了后面检索的时候可以更快速判断是否有合适的构造函数。 -
排序结束后 ,开始遍历构造函数,按照 构造函数的参数类型和数量与构造函数一一匹配,寻找差异性最小的构造函数作为最终的构造函数并通过 cglib 或者 反射来 创建bean。
按照功能划分,整个 autowireConstructor 方法可以划分为四步:
- 解析构造函数参数。
- 获取候选的构造函数列表。
- 解析构造函数参数个数。
- 寻找最匹配的构造函数
1,解析构造函数参数
// explicitArgs通过getBean方法传入
// 如果getBean方法调用的时候指定方法参数那么直接使用
if (explicitArgs != null) {
argsToUse = explicitArgs;
}
else {
// 如果在调用getBean方法的时候没有指定,则尝试从配置文件中解析
Object[] argsToResolve = null;
synchronized (mbd.constructorArgumentLock) {
// 尝试从缓存中获取
constructorToUse = (Constructor<?>) mbd.resolvedConstructorOrFactoryMethod;
if (constructorToUse != null && mbd.constructorArgumentsResolved) {
// Found a cached constructor...
// 从缓存中找到了构造器,那么继续从缓存中寻找缓存的构造器参数
argsToUse = mbd.resolvedConstructorArguments;
if (argsToUse == null) {
// 没有缓存的参数,就需要获取配置i文件中配置的参数
argsToResolve = mbd.preparedConstructorArguments;
}
}
}
// 如果缓存中没有缓存的参数的话,即argsToResolve不为空,就需要解析配置的参数
if (argsToResolve != null) {
// 解析参数类型,比如将配置的String类型转换为list、boolean等类型
argsToUse = resolvePreparedArguments(beanName, mbd, bw, constructorToUse, argsToResolve, true);
}
}
上面的逻辑还是很清楚的:
- 如果有传入参数
explicitArgs
,则直接使用explicitArgs
- 如果没有传入,尝试从缓存中获取
- 如果参数完全解析了,则直接使用,如果没有则调用
resolvePreparedArguments
进行解析。
这里解释一下 resolvePreparedArguments
方法的作用。
我们声明的构造函数的可能是这样的:
public ConstructorDemoA(Integer name) {
this.name = name;
}
但是我们在配置的时候配置文件却是这样的:
<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。
2,获取候选的构造函数列表
// 如果传入的构造器数组不为空,就使用传入的过后早期参数,否则通过反射获取class中定义的构造器
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
方法中。
3,解析构造函数参数个数
// 解析出来的构造函数的个数
int minNrOfArgs;
// 如果explicitArgs不为空,直接使用它作为参数,毕竟是传入的参数,没必要再从进一步解析。
if (explicitArgs != null) {
minNrOfArgs = explicitArgs.length;
}
else {
// 提取配置文件中的配置的构造函数参数
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 ,如下图
但是需要注意的是 这里面保存的是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;
}
4,寻找最匹配的构造函数
代码比较长,上面已经贴出了完整版,这里就简化一下:
...
// 排序构造函数,方便后面检索
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);
}
}
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 代理),默认第二种。
五,无参构造函数实例化
相较于上面的有参构造函数,无参构造函数的解析就简单很多:
protected BeanWrapper instantiateBean(String beanName, RootBeanDefinition mbd) {
try {
Object beanInstance;
if (System.getSecurityManager() != null) {
beanInstance = AccessController.doPrivileged(
(PrivilegedAction<Object>) () -> getInstantiationStrategy().instantiate(mbd, beanName, this),
getAccessControlContext());
}
else {
// 获取实例化策略并且进行实例化操作
beanInstance = getInstantiationStrategy().instantiate(mbd, beanName, this);
}
// 包装成BeanWrapper
BeanWrapper bw = new BeanWrapperImpl(beanInstance);
initBeanWrapper(bw);
return bw;
}
catch (Throwable ex) {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Instantiation of bean failed", ex);
}
}
public Object instantiate(RootBeanDefinition bd, @Nullable String beanName, BeanFactory owner) {
// Don't override the class with CGLIB if no overrides.
// bd对象定义中,是否包含MethodOverride列表,spring中有两个标签参数会产生MethodOverrides,分别是lookup-method,replaced-method
// 没有MethodOverrides对象,可以直接实例化
if (!bd.hasMethodOverrides()) {
// 实例化对象的构造方法
Constructor<?> constructorToUse;
// 锁定对象,使获得实例化构造方法线程安全
synchronized (bd.constructorArgumentLock) {
// 查看bd对象里使用否含有构造方法
constructorToUse = (Constructor<?>) bd.resolvedConstructorOrFactoryMethod;
// 如果没有
if (constructorToUse == null) {
// 从bd中获取beanClass
final Class<?> clazz = bd.getBeanClass();
// 如果要实例化的beanDefinition是一个接口,则直接抛出异常
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中的属性
bd.resolvedConstructorOrFactoryMethod = constructorToUse;
}
catch (Throwable ex) {
throw new BeanInstantiationException(clazz, "No default constructor found", ex);
}
}
}
// 通过反射生成具体的实例化对象
return BeanUtils.instantiateClass(constructorToUse);
}
else {
// Must generate CGLIB subclass.
// 必须生成cglib子类
return instantiateWithMethodInjection(bd, beanName, owner);
}
}
这里可以用一句话概括 : 是否有方法被覆盖(是否使用replace 或 lookup 进行配置),有则使用cglib动态代理,增加方法,否则直接通过反射创建。
六,总结
AbstractAutowireCapableBeanFactory#createBeanInstance
方法处于Spring 创建bean 的入口阶段,完成了bean 的初步创建,调用各种扩展接口来尝试完成bean的创建(Supplier、factory-method),失败了则根据传入参数和和构造函数列表来选择合适的构造函数来创建bean。
但是并未完成属性注入、接口特性实现(如 Aware)、标签设置(如inti-method)的设置。在后续的 AbstractAutowireCapableBeanFactory#populateBean
方法中完成了属性的注入。
推荐阅读
-
spring5 源码深度解析----- 被面试官给虐懵了,竟然是因为我不懂@Configuration配置类及@Bean的原理
-
Spring MVC源码(三) ----- @RequestBody和@ResponseBody原理解析
-
基于Spring注解的上下文初始化过程源码解析(一)
-
Spring源码解析之ConfigurableApplicationContext
-
SpringBoot 源码解析 (七)----- Spring Boot的核心能力 - SpringBoot如何实现SpringMvc的?
-
SpringBoot 源码解析 (六)----- Spring Boot的核心能力 - 内置Servlet容器源码分析(Tomcat)
-
通过实例解析spring bean之间的关系
-
spring源码分析系列5:ApplicationContext的初始化与Bean生命周期
-
spring源码分析6: ApplicationContext的初始化与BeanDefinition的搜集入库
-
PHP中实现汉字转区位码应用源码实例解析