一、前言
文章目录:Spring源码深度解析:文章目录
createBeanInstance()
的流程图如下,让我们根据流程图一步一步的学习一下spring是如何创建bean的吧
这篇文章是接着 Spring源码深度解析:八、bean的获取② - getSingleton 的继续分析过程。
本文主要是分析的方法是AbstractAutowireCapableBeanFactory#createBeanInstance()
,功能是Spring 具体创建bean的过程。调用如下:
二、createBeanInstance 概述
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());
}
// 1. 是否有bean的Supplier接口,如果有,通过回调来创建bean
Supplier<?> instanceSupplier = mbd.getInstanceSupplier();
if (instanceSupplier != null) {
return obtainFromSupplier(instanceSupplier, beanName);
}
// 2. 如果工厂方法不为空,则使用工厂方法初始化策略
// 通过@Bean注解方法注入的bean或者xml配置注入的BeanDefinition会存在这个值。而注入这个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) {
if (mbd.resolvedConstructorOrFactoryMethod != null) {
// 一个类可能有多个不同的构造函数,每个构造函数参数列表不同,所以调用前需要根据参数锁定对应的构造函数或工程方法
// 如果这个bean的构造函数或者工厂方法已经解析过了,会保存到 mbd.resolvedConstructorOrFactoryMethod 中。这里来判断是否已经解析过了。
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方法来获取指定的构造函数列表。后面详解
Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);
if (ctors != null || mbd.getResolvedAutowireMode() == AUTOWIRE_CONSTRUCTOR ||
mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args)) {
return autowireConstructor(beanName, mbd, ctors, args);
}
// 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的创建。
三、createBeanInstance 详解
下面我们来解析代码。
1. 调用 Supplier 接口 - obtainFromSupplier
这部分的功能 : 若RootBeanDefinition
中设置了Supplier
则使用 Supplier
提供的bean替代Spring要生成的bean
Supplier<?> instanceSupplier = mbd.getInstanceSupplier();
if (instanceSupplier != null) {
return obtainFromSupplier(instanceSupplier, beanName);
}
@FunctionalInterface
public interface Supplier<T> {
/**
* Gets a result.
*
* @return a result
*/
T get();
}
AbstractAutowireCapableBeanFactory#obtainFromSupplier()
protected BeanWrapper obtainFromSupplier(Supplier<?> instanceSupplier, String beanName) {
Object instance;
// 使用临时变量保存currentlyCreatedBean当前值
String outerBean = this.currentlyCreatedBean.get();
// 将beanName设置到currentlyCreatedBean中,表示这是当前正在创建到bean
// currentlyCreatedBean.get()在getObjectForBeanInstance中会被调用(通过对currentlyCreatedBean使用find Usages发现)
this.currentlyCreatedBean.set(beanName);
try {
// 执行lambda表达式的 Supplier函数来生成一个实例对象
instance = instanceSupplier.get();
}
finally {
// 还原原来的临时变量
if (outerBean != null) {
this.currentlyCreatedBean.set(outerBean);
}
else {
this.currentlyCreatedBean.remove();
}
}
// 如果得到的实例为null,则会去创建一个空实例
if (instance == null) {
instance = new NullBean();
}
// 构造一个bean包装器,BeanWrapperImpl内初始化了几个参数,无其他逻辑
BeanWrapper bw = new BeanWrapperImpl(instance);
initBeanWrapper(bw);
return bw;
}
- 首先,调用 Supplier 的 get() 方法,获得一个 Bean 实例对象。
- 然后,根据该实例对象构造一个 BeanWrapper 对象 bw 。
- 最后,初始化该对象。
关于其应用场景 : 指定一个用于创建bean实例的回调,以替代声明式指定的工厂方法。主要是考虑反射调用目标方法不如直接调用目标方法效率高。
2. 使用 factory-method 属性 - instantiateUsingFactoryMethod
如果RootBeanDefinition
中存在factoryMethodName
属性,或者在配置文件中配置了factory-method
,Spring会尝试使用instantiateUsingFactoryMethod
方法,根据RootBeanDefinition
中的配置生成bean实例。简单来说,就是如果BeanDefinition
指定了工厂方法,则使用其指定的工厂方法来初始化bean。
简单来说,这里可以分为两种情况
-
在 xml配置中,可以使用
factory-bean
和factory-method
两个标签可以指定一个类中的方法,Spring会将这个指定的方法的返回值作为bean返回(如果方法是静态方法,则可以不创建factorybean
就直接调用,否则需要先将factorybean
注入到Spring中)。 -
对
@Bean
注解的解析。在ConfigurationClassPostProcessor
后处理器中,会对被@Bean
注解修饰的方法进行解析,生成一个ConfigurationClassBeanDefinition
的BeanDefinition
。此时BeanDefinition
的factoryMethodName
正是@Bean
修饰的方法本身。所以这里会调用instantiateUsingFactoryMethod
方法。通过回调的方式调用@Bean
修饰的方法。并将返回结果注入到Spring容器中。
// 2. 如果工厂方法不为空,则使用工厂方法初始化策略
// 通过 @Bean 注解方法注入的bean或者xml配置注入的BeanDefinition会存在这个值。而注入这个bean的方法就是工厂方法。后面会详细解读
if (mbd.getFactoryMethodName() != null) {
// 执行工厂方法,创建bean
return instantiateUsingFactoryMethod(beanName, mbd, args);
}
ConstructorResolver#instantiateUsingFactoryMethod()
public BeanWrapper instantiateUsingFactoryMethod(
String beanName, RootBeanDefinition mbd, @Nullable Object[] explicitArgs) {
//构造bean的包装类
BeanWrapperImpl bw = new BeanWrapperImpl();
//初始化包装类
this.beanFactory.initBeanWrapper(bw);
Object factoryBean;
Class<?> factoryClass;
boolean isStatic;
//获得bean的工厂名字
String factoryBeanName = mbd.getFactoryBeanName();
//假如不为空
if (factoryBeanName != null) {
//假如bean的工厂名和bean名字相同
if (factoryBeanName.equals(beanName)) {
throw new BeanDefinitionStoreException(mbd.getResourceDescription(), beanName,
"factory-bean reference points back to the same bean definition");
}
//根据名字获得bean的工厂
factoryBean = this.beanFactory.getBean(factoryBeanName);
//假如bean是单例,且工厂已经存在
if (mbd.isSingleton() && this.beanFactory.containsSingleton(beanName)) {
throw new ImplicitlyAppearedSingletonException();
}
// 获得工厂字节码
factoryClass = factoryBean.getClass();
isStatic = false;
}
else {
// 工厂名为空,则其可能是一个静态工厂
// 静态工厂创建bean,必须要提供工厂的全类名
// It's a static factory method on the bean class.
if (!mbd.hasBeanClass()) {
throw new BeanDefinitionStoreException(mbd.getResourceDescription(), beanName,
"bean definition declares neither a bean class nor a factory-bean reference");
}
factoryBean = null;
factoryClass = mbd.getBeanClass();
isStatic = true;
}
// 获得 factoryMethodToUse、argsHolderToUse、argsToUse 属性
Method factoryMethodToUse = null;
ArgumentsHolder argsHolderToUse = null;
Object[] argsToUse = null;
// 如果指定了构造方法的参数,则构造bean 的时候使用此构造方法
if (explicitArgs != null) {
argsToUse = explicitArgs;
}
else {
// 没有指定,则尝试从配置文件中解析
Object[] argsToResolve = null;
synchronized (mbd.constructorArgumentLock) {
// 尝试用构造工厂中获取
factoryMethodToUse = (Method) mbd.resolvedConstructorOrFactoryMethod;
if (factoryMethodToUse != null && mbd.constructorArgumentsResolved) {
// Found a cached factory method...
// 尝试从缓存中获取
argsToUse = mbd.resolvedConstructorArguments;
if (argsToUse == null) {
// 获取缓存中的构造函数参数的包可见字段
argsToResolve = mbd.preparedConstructorArguments;
}
}
}
// 缓存中存在,则解析存储在 BeanDefinition 中的参数
// 如给定方法的构造函数 A(int ,int ),则通过此方法后就会把配置文件中的("1","1")转换为 (1,1)
// 缓存中的值可能是原始值也有可能是最终值
if (argsToResolve != null) {
argsToUse = resolvePreparedArguments(beanName, mbd, bw, factoryMethodToUse, argsToResolve);
}
}
if (factoryMethodToUse == null || argsToUse == null) {
// Need to determine the factory method...
// Try all methods with this name to see if they match the given arguments.
// 获取工厂方法的全名称
factoryClass = ClassUtils.getUserClass(factoryClass);
// 获取所有的待定方法
Method[] rawCandidates = getCandidateMethods(factoryClass, mbd);
List<Method> candidateList = new ArrayList<>();
// 检索所有方法,这里是对方法进行过滤
for (Method candidate : rawCandidates) {
// 如果有方法为静态方法,且为工厂方法则添加到candidateList中
if (Modifier.isStatic(candidate.getModifiers()) == isStatic && mbd.isFactoryMethod(candidate)) {
candidateList.add(candidate);
}
}
// 排序构造函数
Method[] candidates = candidateList.toArray(new Method[0]);
// public 构造函数优先参数数量降序,非 public 构造函数参数数量降序
AutowireUtils.sortFactoryMethods(candidates);
// 用来承载解析后构造函数的值
ConstructorArgumentValues resolvedValues = null;
boolean autowiring = (mbd.getResolvedAutowireMode() == AutowireCapableBeanFactory.AUTOWIRE_CONSTRUCTOR);
int minTypeDiffWeight = Integer.MAX_VALUE;
Set<Method> ambiguousFactoryMethods = null;
int minNrOfArgs;
if (explicitArgs != null) {
minNrOfArgs = explicitArgs.length;
}
else {
// We don't have arguments passed in programmatically, so we need to resolve the
// arguments specified in the constructor arguments held in the bean definition.
// 如果getBean没有传递参数,则需要解析保存在 BeanDefinition 构造函数中指定的参数
if (mbd.hasConstructorArgumentValues()) {
// 构造函数的参数
ConstructorArgumentValues cargs = mbd.getConstructorArgumentValues();
resolvedValues = new ConstructorArgumentValues();
// 将构造函数的参数解析进resolvedValues中
minNrOfArgs = resolveConstructorArguments(beanName, mbd, bw, cargs, resolvedValues);
}
else {
minNrOfArgs = 0;
}
}
LinkedList<UnsatisfiedDependencyException> causes = null;
// 遍历 candidates 数组
for (Method candidate : candidates) {
// 方法体的参数
Class<?>[] paramTypes = candidate.getParameterTypes();
if (paramTypes.length >= minNrOfArgs) {
// 保存参数的对象
ArgumentsHolder argsHolder;
// 传递了参数
if (explicitArgs != null) {
// Explicit arguments given -> arguments length must match exactly.
// 显示给定参数,参数长度必须完全匹配
if (paramTypes.length != explicitArgs.length) {
continue;
}
// 根据参数创建参数持有者 ArgumentsHolder 对象
argsHolder = new ArgumentsHolder(explicitArgs);
}
else {
// 未提供参数
// Resolved constructor arguments: type conversion and/or autowiring necessary.
try {
String[] paramNames = null;
// 获取 ParameterNameDiscoverer 对象
ParameterNameDiscoverer pnd = this.beanFactory.getParameterNameDiscoverer();
if (pnd != null) {
// 获取指定构造函数的参数名称
paramNames = pnd.getParameterNames(candidate);
}
// 在已经解析的构造函数参数值的情况下,创建一个参数持有者 ArgumentsHolder 对象
argsHolder = createArgumentArray(
beanName, mbd, resolvedValues, bw, paramTypes, paramNames, candidate, autowiring);
}
catch (UnsatisfiedDependencyException ex) {
if (logger.isTraceEnabled()) {
logger.trace("Ignoring factory method [" + candidate + "] of bean '" + beanName + "': " + ex);
}
// Swallow and try next overloaded factory method.
if (causes == null) {
causes = new LinkedList<>();
}
causes.add(ex);
continue;
}
}
// isLenientConstructorResolution 判断解析构造函数的时候是否以宽松模式还是严格模式
// 严格模式:解析构造函数时,必须所有的都需要匹配,否则抛出异常
// 宽松模式:使用具有"最接近的模式"进行匹配
// typeDiffWeight:类型差异权重
int typeDiffWeight = (mbd.isLenientConstructorResolution() ?
argsHolder.getTypeDifferenceWeight(paramTypes) : argsHolder.getAssignabilityWeight(paramTypes));
// Choose this factory method if it represents the closest match.
// 代表最接近的类型匹配,则选择作为构造函数
if (typeDiffWeight < minTypeDiffWeight) {
factoryMethodToUse = candidate;
argsHolderToUse = argsHolder;
argsToUse = argsHolder.arguments;
minTypeDiffWeight = typeDiffWeight;
ambiguousFactoryMethods = null;
}
// Find out about ambiguity: In case of the same type difference weight
// for methods with the same number of parameters, collect such candidates
// and eventually raise an ambiguity exception.
// However, only perform that check in non-lenient constructor resolution mode,
// and explicitly ignore overridden methods (with the same parameter signature).
// 如果具有相同参数数量的方法具有相同的类型差异权重,则收集此类型选项
// 但是,仅在非宽松构造函数解析模式下执行该检查,并显式忽略重写方法(具有相同的参数签名)
else if (factoryMethodToUse != null && typeDiffWeight == minTypeDiffWeight &&
!mbd.isLenientConstructorResolution() &&
paramTypes.length == factoryMethodToUse.getParameterCount() &&
!Arrays.equals(paramTypes, factoryMethodToUse.getParameterTypes())) {
if (ambiguousFactoryMethods == null) {
ambiguousFactoryMethods = new LinkedHashSet<>();
// 存在多个可选方法
ambiguousFactoryMethods.add(factoryMethodToUse);
}
ambiguousFactoryMethods.add(candidate);
}
}
}
// 没有可执行的工厂方法,抛出异常
if (factoryMethodToUse == null) {
if (causes != null) {
UnsatisfiedDependencyException ex = causes.removeLast();
for (Exception cause : causes) {
this.beanFactory.onSuppressedException(cause);
}
throw ex;
}
List<String> argTypes = new ArrayList<>(minNrOfArgs);
if (explicitArgs != null) {
for (Object arg : explicitArgs) {
argTypes.add(arg != null ? arg.getClass().getSimpleName() : "null");
}
}
else if (resolvedValues != null) {
Set<ValueHolder> valueHolders = new LinkedHashSet<>(resolvedValues.getArgumentCount());
valueHolders.addAll(resolvedValues.getIndexedArgumentValues().values());
valueHolders.addAll(resolvedValues.getGenericArgumentValues());
for (ValueHolder value : valueHolders) {
String argType = (value.getType() != null ? ClassUtils.getShortName(value.getType()) :
(value.getValue() != null ? value.getValue().getClass().getSimpleName() : "null"));
argTypes.add(argType);
}
}
String argDesc = StringUtils.collectionToCommaDelimitedString(argTypes);
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"No matching factory method found: " +
(mbd.getFactoryBeanName() != null ?
"factory bean '" + mbd.getFactoryBeanName() + "'; " : "") +
"factory method '" + mbd.getFactoryMethodName() + "(" + argDesc + ")'. " +
"Check that a method with the specified name " +
(minNrOfArgs > 0 ? "and arguments " : "") +
"exists and that it is " +
(isStatic ? "static" : "non-static") + ".");
}
else if (void.class == factoryMethodToUse.getReturnType()) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Invalid factory method '" + mbd.getFactoryMethodName() +
"': needs to have a non-void return type!");
}
else if (ambiguousFactoryMethods != null) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Ambiguous factory method matches found in bean '" + beanName + "' " +
"(hint: specify index/type/name arguments for simple parameters to avoid type ambiguities): " +
ambiguousFactoryMethods);
}
if (explicitArgs == null && argsHolderToUse != null) {
argsHolderToUse.storeCache(mbd, factoryMethodToUse);
}
}
try {
Object beanInstance;
if (System.getSecurityManager() != null) {
final Object fb = factoryBean;
final Method factoryMethod = factoryMethodToUse;
final Object[] args = argsToUse;
beanInstance = AccessController.doPrivileged((PrivilegedAction<Object>) () ->
beanFactory.getInstantiationStrategy().instantiate(mbd, beanName, beanFactory, fb, factoryMethod, args),
beanFactory.getAccessControlContext());
}
else {
beanInstance = this.beanFactory.getInstantiationStrategy().instantiate(
mbd, beanName, this.beanFactory, factoryBean, factoryMethodToUse, argsToUse);
}
// 创建 Bean 对象,并设置到 bw 中
bw.setBeanInstance(beanInstance);
return bw;
}
catch (Throwable ex) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Bean instantiation via factory method failed", ex);
}
}
2.1 storeCache将构造函数、构造参数保存到缓存中
ConstructorResolver#storeCache()
public void storeCache(RootBeanDefinition mbd, Executable constructorOrFactoryMethod) {
// 构造函数的缓存锁
synchronized (mbd.constructorArgumentLock) {
// 缓存已经解析的构造函数或者工厂方法
mbd.resolvedConstructorOrFactoryMethod = constructorOrFactoryMethod;
// 标记字段,标记构造函数、参数已经解析了。默认为 false
mbd.constructorArgumentsResolved = true;
if (this.resolveNecessary) {
// 缓存已经解析的构造函数参数,包可见字段
mbd.preparedConstructorArguments = this.preparedArguments;
}
else {
mbd.resolvedConstructorArguments = this.arguments;
}
}
}
2.2instantiate创建Bean
InstantiationStrategy#instantiate()
Object instantiate(RootBeanDefinition bd, @Nullable String beanName, BeanFactory owner,
@Nullable Object factoryBean, Method factoryMethod, @Nullable Object... args)
throws BeansException;
SimpleInstantiationStrategy#instantiate()
public Object instantiate(RootBeanDefinition bd, @Nullable String beanName, BeanFactory owner,
@Nullable Object factoryBean, final Method factoryMethod, Object... args) {
try {
// 设置 Method 可访问
if (System.getSecurityManager() != null) {
AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
ReflectionUtils.makeAccessible(factoryMethod);
return null;
});
}
else {
ReflectionUtils.makeAccessible(factoryMethod);
}
// 获得原 Method 对象
Method priorInvokedFactoryMethod = currentlyInvokedFactoryMethod.get();
try {
// 设置新的 Method 对象,到 currentlyInvokedFactoryMethod 中
currentlyInvokedFactoryMethod.set(factoryMethod);
// 创建bean
Object result = factoryMethod.invoke(factoryBean, args);
// bean不存在则创建nullbean
if (result == null) {
result = new NullBean();
}
return result;
}
finally {
if (priorInvokedFactoryMethod != null) {
currentlyInvokedFactoryMethod.set(priorInvokedFactoryMethod);
}
else {
currentlyInvokedFactoryMethod.remove();
}
}
}
catch (IllegalArgumentException ex) {
throw new BeanInstantiationException(factoryMethod,
"Illegal arguments to factory method '" + factoryMethod.getName() + "'; " +
"args: " + StringUtils.arrayToCommaDelimitedString(args), ex);
}
catch (IllegalAccessException ex) {
throw new BeanInstantiationException(factoryMethod,
"Cannot access factory method '" + factoryMethod.getName() + "'; is it public?", ex);
}
catch (InvocationTargetException ex) {
String msg = "Factory method '" + factoryMethod.getName() + "' threw exception";
if (bd.getFactoryBeanName() != null && owner instanceof ConfigurableBeanFactory &&
((ConfigurableBeanFactory) owner).isCurrentlyInCreation(bd.getFactoryBeanName())) {
msg = "Circular reference involving containing bean '" + bd.getFactoryBeanName() + "' - consider " +
"declaring the factory method as static for independence from its containing instance. " + msg;
}
throw new BeanInstantiationException(factoryMethod, msg, ex.getTargetException());
}
}
3. 构造函数的缓存判断
到达这一步,Spring则打算通过bean的构造函数来创建bean。但是一个bean可能会存在多个构造函数,这时候Spring会根据参数列表的来判断使用哪个构造函数进行实例化。但是判断过程比较消耗性能,所以Spring将判断好的构造函数缓存到RootBeanDefinition
中,如果不存在缓存则进行构造函数的筛选并缓存解析结果。RootBeanDefinition 中具体的缓存属性有如下几个:
RootBeanDefinition 中主要使用如下几个属性缓存 :
resolvedConstructorOrFactoryMethod
: 用于缓存已解析的构造函数或工厂方法constructorArgumentsResolved
:这个字段有两层含义: 一,标记构造函数是否已经完成解析。二,标志这个bean的加载是否需要通过构造注入(autowireConstructor
) 的方式加载。因为只有在autowireConstructor
方法中才会将其置为 true。resolvedConstructorArguments
: 缓存解析好的构造函数的入参
// 经过上面两步,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);
}
}
4. 带有参数的构造函数实例化 - autowireConstructor
上面的代码我们可以看到,Bean的的创建,分为有参构造函数和无参构造函数两种方式进行创建,对于有参构造函数,使用的就是该方法进行处理。这个代码量非常巨大,实现的功能实现上比较复杂,功能上却可以一句话讲清,简单来说,就是根据传入的参数列表,来匹配到合适的构造函数进行bean 的创建。
autowireConstructor(beanName, mbd, null, null);
autowireConstructor
的代码比较复杂,详细代码如下:
AbstractAutowireCapableBeanFactory#autowireConstructor()
protected BeanWrapper autowireConstructor(
String beanName, RootBeanDefinition mbd, @Nullable Constructor<?>[] ctors, @Nullable Object[] explicitArgs) {
return new ConstructorResolver(this).autowireConstructor(beanName, mbd, ctors, explicitArgs);
}
ConstructorResolver#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);
}
}
// 如果构造函数 和 构造函数入参都不为空,则可以直接生成bean。否则的话,需要通过一定的规则进行筛选
if (constructorToUse == null) {
// 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);
}
// 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);
}
}
// 3. 寻找最匹配的构造函数
// 对构造函数列表进行排序: public 构造函数优先参数数量降序,非public构造函数参数数量降序
AutowireUtils.sortConstructors(candidates);
int minTypeDiffWeight = Integer.MAX_VALUE;
Set<Constructor<?>> ambiguousConstructors = null;
LinkedList<UnsatisfiedDependencyException> causes = null;
// 遍历构造函数,寻找合适的构造函数
for (Constructor<?> candidate : candidates) {
Class<?>[] paramTypes = candidate.getParameterTypes();
// 如果构造函数存在参数,resolvedValues 是上面解析后的构造函数,有参则根据 值 构造对应参数类型的参数
if (constructorToUse != null && argsToUse.length > paramTypes.length) {
// Already found greedy constructor that can be satisfied ->
// do not look any further, there are only less greedy constructors left.
break;
}
if (paramTypes.length < minNrOfArgs) {
continue;
}
ArgumentsHolder argsHolder;
if (resolvedValues != null) {
try {
// 获取参数名称
String[] paramNames = ConstructorPropertiesChecker.evaluate(candidate, paramTypes.length);
// 为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);
}
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 (paramTypes.length != 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.storeCache(mbd, constructorToUse);
}
}
try {
final InstantiationStrategy strategy = beanFactory.getInstantiationStrategy();
Object beanInstance;
if (System.getSecurityManager() != null) {
final Constructor<?> ctorToUse = constructorToUse;
final Object[] argumentsToUse = argsToUse;
beanInstance = AccessController.doPrivileged((PrivilegedAction<Object>) () ->
strategy.instantiate(mbd, beanName, beanFactory, ctorToUse, argumentsToUse),
beanFactory.getAccessControlContext());
}
else {
beanInstance = strategy.instantiate(mbd, beanName, this.beanFactory, constructorToUse, argsToUse);
}
// 将构建的实例加入BeanWrapper 中
bw.setBeanInstance(beanInstance);
return bw;
}
catch (Throwable ex) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Bean instantiation via constructor failed", ex);
}
}
简单理一下上面的逻辑:
- 首先判断
explicitArgs
是否为空,如果不为空,则就直接使用explicitArgs
作为构造函数的参数。
explicitArgs
所代表的意思是 调用getBean方法是的传参,代码中可以看到,如果explicitArgs
不为空,那么并未从缓存中获取构造函数(个人猜测 getBean 方法调用参数并不一致,可能缓存并不适用) 如下:
- 如果
explicitArgs
为空,则尝试从之缓存中获取,也即是从RootBeanDefinition
的resolvedConstructorArguments
属性或preparedConstructorArguments
属性中获取。resolvedConstructorArguments
代表完全解析好的参数,preparedConstructorArguments
代表尚未完全解析的参数,如果获取到preparedConstructorArguments
,则需要在进一步的解析。 - 如果缓存中也没有获取到,则只能自己开始分析来获取候选构造函数列表,关于候选构造函数的信息,在调用该方法时就已经传递了过来,即
Constructor<?>[] chosenCtors
,如果Constructor<?>[] chosenCtors
为null
,则通过反射获取候选构造函数列表candidates
- 获取到候选构造函数列表
candidates
后,则会优先判断获取到的candidates
是否只有一个构造函数,如果只要一个,则不需要解析,直接保存相关信息即解析完毕。 - 否则则进行候选构造函数列表
candidates
的选举,寻找最合适的构造函数,对candidates
按照public
构造函数优先参数数量降序,非public
构造函数参数数量降序 规则排序,目的是为了后面检索的时候可以更快速判断是否有合适的构造函数。
排序结束后 ,开始遍历构造函数,按照 构造函数的参数类型和数量与构造函数一一匹配,寻找差异性最小的构造函数作为最终的构造函数并通过cglib
或者反射来创建bean
。
按照功能划分,整个 autowireConstructor 方法可以划分为四步:
- 解析构造函数参数
- 获取候选的构造函数列表
- 解析构造函数参数个数
- 寻找最匹配的构造函数
下面分段解析:
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
。
4.2 获取候选的构造函数列表
// 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);
}
}
这个逻辑也是比较清楚的 chosenCtors 是传入的构造函数列表
- 外部是否传入了候选构造函数列表( chosenCtors == null)
- 如果没传入(chosenCtors 为null),通过反射获取构造函数列表
这里需要注意点是 传入的chosenCtors
,在不同的调用场景下可能会传入null,或者 调用 SmartInstantiationAwareBeanPostProcessor.determineCandidateConstructors
方法返回的值。Spring 默认的实现是在 AutowiredAnnotationBeanPostProcessor.determineCandidateConstructors
方法中。
4.3 寻找最匹配的构造函数
到这里,我们可以知道 minNrOfArgs 为最终构造函数入参数量;candidates 是供选择的构造函数列表。
代码比较长,上面已经贴出了完整版,这里就简化一下。
// 3. 寻找最匹配的构造函数
// 对构造函数列表进行排序: public 构造函数优先参数数量降序,非public构造函数参数数量降序
AutowireUtils.sortConstructors(candidates);
int minTypeDiffWeight = Integer.MAX_VALUE;
Set<Constructor<?>> ambiguousConstructors = null;
LinkedList<UnsatisfiedDependencyException> causes = null;
// 遍历构造函数,寻找合适的构造函数
for (Constructor<?> candidate : candidates) {
Class<?>[] paramTypes = candidate.getParameterTypes();
// 如果构造函数存在参数,resolvedValues 是上面解析后的构造函数,有参则根据 值 构造对应参数类型的参数
if (constructorToUse != null && argsToUse.length > paramTypes.length) {
// Already found greedy constructor that can be satisfied ->
// do not look any further, there are only less greedy constructors left.
break;
}
if (paramTypes.length < minNrOfArgs) {
continue;
}
ArgumentsHolder argsHolder;
if (resolvedValues != null) {
try {
// 获取参数名称
String[] paramNames = ConstructorPropertiesChecker.evaluate(candidate, paramTypes.length);
// 为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);
}
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 (paramTypes.length != 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.storeCache(mbd, constructorToUse);
}
}
try {
final InstantiationStrategy strategy = beanFactory.getInstantiationStrategy();
Object beanInstance;
if (System.getSecurityManager() != null) {
final Constructor<?> ctorToUse = constructorToUse;
final Object[] argumentsToUse = argsToUse;
beanInstance = AccessController.doPrivileged((PrivilegedAction<Object>) () ->
strategy.instantiate(mbd, beanName, beanFactory, ctorToUse, argumentsToUse),
beanFactory.getAccessControlContext());
}
else {
beanInstance = strategy.instantiate(mbd, beanName, this.beanFactory, constructorToUse, argsToUse);
}
// 将构建的实例加入BeanWrapper 中
bw.setBeanInstance(beanInstance);
return bw;
}
catch (Throwable ex) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Bean instantiation via constructor failed", ex);
}
这一步的目的就是根据参数数量和参数列表来选择最合适的构造函数,并且调用instantiate(beanName, mbd, constructorToUse, argsToUse)
方法来创建bean实例。
下面提三点:
- 由于在配置文件中声明bean不仅仅可以使用参数位置索引的方式创建,也支持通过参数名称设定参数值的情况,如下:
<constructor-arg name="constructorDemoB" ref="constructorDemoB"></constructor-arg>
所以这时候,就需要首先确定构造函数中的参数名称。而获取参数名的方式有两种,一种是通过注解直接获取(@ConstructorProperties
注解获取),即上面代码中对应的 ConstructorPropertiesChecker.evaluate(candidate, parameterCount);
,另一种是通过Spring同构的工具类ParameterNameDiscoverer
,这个在代码中也有使用。
完成这一步的时候,构造函数、参数名称、参数类型、参数值都确定后就可以锁定构造函数以及转换对应的参数类型了。
2. 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. 无参构造函数实例化 - instantiateBean
相较于上面的有参构造函数,无参构造函数的解析显的那么简单
AbstractAutowireCapableBeanFactory#instantiateBean()
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 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)
中,其细代码如下:
@Override
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
6. 构造函数的筛选
在bean第一次创建的时候,并不存在构造缓存,所以会执行下面的代码。也就是说,这里是Bean第一次创建所调用的代码。
// 6. 根据参数解析构造函数,并将解析出来的构造函数缓存到mdb的resolvedConstructorOrFactoryMethod属性中
// 到这一步,说明 bean 是第一次加载,所以没有对构造函数进行相关缓存(resolved 为 false)
// 调用 determineConstructorsFromBeanPostProcessors方法来获取指定的构造函数列表。
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);
}
// No special handling: simply use no-arg constructor.
// 使用默认构造函数构造
return instantiateBean(beanName, mbd);
这里可以看到,如果没有进行任何额外的配置的话,会使用默认的方式(instantiateBean(beanName, mbd)
)创建bean。
我们这里整理一下调用autowireConstructor
方法的条件(以下条件满足其一即可):
-
ctors != null :determineConstructorsFromBeanPostProcessors
方法筛选出的候选构造函数不为null。对于默认的Spring来说,实际返回的是AutowiredAnnotationBeanPostProcessor#determineCandidateConstructors
方法的返回值。而其作用简单来说就是返回被@Autowired
注解修饰的构造函数(实际要更为复杂,这里可以简单这样理解),如下: -
-
mbd.getResolvedAutowireMode() == AUTOWIRE_CONSTRUCTOR
:这里的配置是通过xml 来配置bean时指定的装配方式,如果指定了构造装配,则调用autowireConstructor
方法。如下:
-
mbd.hasConstructorArgumentValues()
:这里表示是否给当前bean定义了构造函数入参。通过xml配置bean的时候可以通过constructor-arg
标签指定构造函数入参。如下
-
!ObjectUtils.isEmpty(args)
: 在通过getBean
方法以编程方式传递的参数值args。如果有,使用其作为bean创建时构造函数的参数。 -
mbd.getPreferredConstructors() != null
:RootBeanDefinition
的实现是 null 。这里仅在GenericApplicationContext.ClassDerivedBeanDefinition
中有过解析。
关于determineConstructorsFromBeanPostProcessors
方法,实际返回的是AutowiredAnnotationBeanPostProcessor#determineCandidateConstructors
方法的返回值。
四、 总结
AbstractAutowireCapableBeanFactory#createBeanInstance
方法处于Spring 创建bean 的入口阶段,完成了bean 的初步创建,调用各种扩展接口来尝试完成bean的创建(Supplier、factory-method),失败了则根据传入参数和和构造函数列表来选择合适的构造函数来创建bean。
但是并未完成属性注入、接口特性实现(如 Aware)、标签设置(如inti-method)的设置。在后续的 AbstractAutowireCapableBeanFactory#populateBean
方法中完成了属性的注入。
需要注意的是,当一个bean第一次被解析时判断调用autowireConstructor
方法来进行创建的时候,那么后面再次解析该bean仍会通过autowireConstructor
方法进行解析。因为 autowireConstructor
方法中在添加缓存的时候将constructorArgumentsResolved
置为true来确保下一次解析时仍调用autowireConstructor
方法