前言:上篇文章末尾提到createBeanInstance方法中使用工厂方法实例化Bean对象,本文将对该方法进行分析。


AbstractAutowireCapableBeanFactory#instantiateUsingFactoryMethod

     protected BeanWrapper instantiateUsingFactoryMethod(
String beanName, RootBeanDefinition mbd, @Nullable Object[] explicitArgs) { return new ConstructorResolver(this).instantiateUsingFactoryMethod(beanName, mbd, explicitArgs);
}

可以看到这里是委托给ConstructorResolver来实现的:

 // ConstructorResolver
public BeanWrapper instantiateUsingFactoryMethod(
String beanName, RootBeanDefinition mbd, @Nullable Object[] explicitArgs) {
// 构造BeanWrapperImpl对象
BeanWrapperImpl bw = new BeanWrapperImpl();
// 初始化BeanWrapperImpl 向BeanWrapper对象中添加ConversionService对象和属性编辑器PropertyEditor对象
this.beanFactory.initBeanWrapper(bw); // 获得factoryBean、factoryClass、isStatic、factoryBeanName属性
Object factoryBean;
Class<?> factoryClass;
boolean isStatic; String factoryBeanName = mbd.getFactoryBeanName();
// 工厂名不为空
if (factoryBeanName != null) {
// 如果工厂名和beanName相等,则抛出BeanDefinitionStoreException异常
if (factoryBeanName.equals(beanName)) {
throw new BeanDefinitionStoreException(mbd.getResourceDescription(), beanName,
"factory-bean reference points back to the same bean definition");
}
// 获取工厂实例
factoryBean = this.beanFactory.getBean(factoryBeanName);
// 如果是单例模式,并且已经缓存中已经存在beanName则抛出异常
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; // 如果指定了构造参数则直接使用
// 在调用getBean方法的时候指定方法参数
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中的参数
// 如给定方法的构造函数 f(int ,int),通过此方法后就会把配置文件中的("1","1")转换为(1,1)
// 缓存中的值可能是原始值,也可能是最终值
if (argsToResolve != null) {
argsToUse = resolvePreparedArguments(beanName, mbd, bw, factoryMethodToUse, argsToResolve, true);
}
} 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); List<Method> candidateList = null;
// 同步
if (mbd.isFactoryMethodUnique) {
// 获取工厂方法
if (factoryMethodToUse == null) {
factoryMethodToUse = mbd.getResolvedFactoryMethod();
}
// 获取所有待定的工厂方法
if (factoryMethodToUse != null) {
candidateList = Collections.singletonList(factoryMethodToUse);
}
}
// 如果工厂方法为空,则通过getCandidateMethods获取所有的待定方法
if (candidateList == null) {
candidateList = new ArrayList<>();
Method[] rawCandidates = getCandidateMethods(factoryClass, mbd);
for (Method candidate : rawCandidates) {
if (Modifier.isStatic(candidate.getModifiers()) == isStatic && mbd.isFactoryMethod(candidate)) {
candidateList.add(candidate);
}
}
} // 通过工厂方法创建bean
if (candidateList.size() == 1 && explicitArgs == null && !mbd.hasConstructorArgumentValues()) {
Method uniqueCandidate = candidateList.get(0);
if (uniqueCandidate.getParameterCount() == 0) {
mbd.factoryMethodToIntrospect = uniqueCandidate;
synchronized (mbd.constructorArgumentLock) {
mbd.resolvedConstructorOrFactoryMethod = uniqueCandidate;
mbd.constructorArgumentsResolved = true;
mbd.resolvedConstructorArguments = EMPTY_ARGS;
}
bw.setBeanInstance(instantiate(beanName, mbd, factoryBean, uniqueCandidate, EMPTY_ARGS));
return bw;
}
} 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();
// 解析构造函数参数
// 将bean的构造函数解析为resolvedValues对象,其中会涉及到其他的bean
minNrOfArgs = resolveConstructorArguments(beanName, mbd, bw, cargs, resolvedValues);
} else {
minNrOfArgs = 0;
}
} // 记录UnsatisfiedDependencyException异常集合
LinkedList<UnsatisfiedDependencyException> causes = null; // 遍历candidates
for (Method candidate : candidates) {
// 方法体参数
Class<?>[] paramTypes = candidate.getParameterTypes(); if (paramTypes.length >= minNrOfArgs) {
// 保存参数对象
ArgumentsHolder argsHolder;
// getBean()传递了参数
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用于解析方法和构造函数的参数名,为参数名称探测器
ParameterNameDiscoverer pnd = this.beanFactory.getParameterNameDiscoverer();
// 获取指定构造函数的参数名
if (pnd != null) {
paramNames = pnd.getParameterNames(candidate);
}
// 在已解析构造函数参数值的情况下,创建一个参数持有者ArgumentsHolder对象
argsHolder = createArgumentArray(beanName, mbd, resolvedValues, bw,
paramTypes, paramNames, candidate, autowiring, candidates.length == 1);
} 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<>();
}
// 发生UnsatisfiedDependencyException异常,添加到causes中
causes.add(ex);
continue;
}
} // isLenientConstructorResolution判断解析构造函数的时候是否以宽松模式还是严格模式
// 宽松模式:使用具有"最接近的模式"进行匹配
// 严格模式:解析构造函数时,必须所有的都需要匹配,否则抛出异常
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 || argsToUse == 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) {
mbd.factoryMethodToIntrospect = factoryMethodToUse;
argsHolderToUse.storeCache(mbd, factoryMethodToUse);
}
} // 创建bean对象,并设置到BeanWrapperImpl中
bw.setBeanInstance(instantiate(beanName, mbd, factoryBean, factoryMethodToUse, argsToUse));
return bw;
}

分析:

由于该方法实在是太长了,因此对其进行分段分析。

#1 首先初始化了BeanwrapperImpl,需确认工厂对象,获取工厂名称,如果工厂名不为null,则走如下流程:

       String factoryBeanName = mbd.getFactoryBeanName();
// 工厂名不为空
if (factoryBeanName != null) {
// 如果工厂名和beanName相等,则抛出BeanDefinitionStoreException异常
if (factoryBeanName.equals(beanName)) {
throw new BeanDefinitionStoreException(mbd.getResourceDescription(), beanName,
"factory-bean reference points back to the same bean definition");
}
// 获取工厂实例
factoryBean = this.beanFactory.getBean(factoryBeanName);
// 如果是单例模式,并且已经缓存中已经存在beanName则抛出异常
if (mbd.isSingleton() && this.beanFactory.containsSingleton(beanName)) {
throw new ImplicitlyAppearedSingletonException();
}
factoryClass = factoryBean.getClass();
isStatic = false;
}

分析:

  • 如果factoryBeanName与beanName一样,则抛出BeanDefinitionStoreException异常。
  • 然后通过AbstractBeanFactory#getBean方法获取工厂实例对象。
  • 如果BeanDefinition为单例模式,且singletonObjects缓存中已经存在该bean对象了,则抛出异常。因为单例模式下且缓存中存在是不需要再次创建bean对象的,单例模式的bean只会实例化一次。

如果工厂名为null,则走如下分支:

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

分析:

  • 如果BeanDefinition中没有解析类,则抛出异常,异常信息也描述得非常清晰:"bean definition的描述中既没有bean class也没有工厂的引用。
  • 将factoryClass设置为BeanDefinition的beanClass,并将isStatic=true,表明可能存在一个静态工厂。

#2 工厂对象确认后,需确认构造参数。

#2.1 如果explicitArgs存在,则直接使用该参数。explicitArgs是调用getBean方法的入参,如果该参数不为null,则可以确定构造函数的参数就是它了。

     // 确定构造参数
// 如果getBean()已传递,则直接使用
if (explicitArgs != null) {
argsToUse = explicitArgs;
}

#2.2 如果未传入构造参数,则走如下分支:

 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中的参数
// 如给定方法的构造函数 f(int ,int),通过此方法后就会把配置文件中的("1","1")转换为(1,1)
// 缓存中的值可能是原始值,也可能是最终值
if (argsToResolve != null) {
argsToUse = resolvePreparedArguments(beanName, mbd, bw, factoryMethodToUse, argsToResolve, true);
}
}

分析:

整个流程其实就是尝试从缓存中获取构造函数参数,如果存在则通过resolvePreparedArguments进行转换,由于缓存中的值可能是最终值,也可能不是最终值。比如构造函数中的类型为Integer类型的1,但缓存中的类型有可能是String类型的"1",所以即便是从缓存中得到了构造参数,也需要经过一番的类型转换才能确保参数类型完全对应。关于resolvePreparedArguments函数的解析,将在后续文章中体现。

#2.3 如果缓存中未获取到构造参数,则走如下分支:

 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); List<Method> candidateList = null;
// 同步
if (mbd.isFactoryMethodUnique) {
// 获取工厂方法
if (factoryMethodToUse == null) {
factoryMethodToUse = mbd.getResolvedFactoryMethod();
}
// 获取所有待定的工厂方法
if (factoryMethodToUse != null) {
candidateList = Collections.singletonList(factoryMethodToUse);
}
}
// 如果工厂方法为空,则通过getCandidateMethods获取所有的待定方法
if (candidateList == null) {
candidateList = new ArrayList<>();
Method[] rawCandidates = getCandidateMethods(factoryClass, mbd);
for (Method candidate : rawCandidates) {
if (Modifier.isStatic(candidate.getModifiers()) == isStatic && mbd.isFactoryMethod(candidate)) {
candidateList.add(candidate);
}
}
} // 通过工厂方法创建bean
if (candidateList.size() == 1 && explicitArgs == null && !mbd.hasConstructorArgumentValues()) {
Method uniqueCandidate = candidateList.get(0);
if (uniqueCandidate.getParameterCount() == 0) {
mbd.factoryMethodToIntrospect = uniqueCandidate;
synchronized (mbd.constructorArgumentLock) {
mbd.resolvedConstructorOrFactoryMethod = uniqueCandidate;
mbd.constructorArgumentsResolved = true;
mbd.resolvedConstructorArguments = EMPTY_ARGS;
}
bw.setBeanInstance(instantiate(beanName, mbd, factoryBean, uniqueCandidate, EMPTY_ARGS));
return bw;
}
}

分析:

如果在缓存中未到构造参数,则尝试通过native方法获取工厂方法类的全类名,如果得到工厂方法只有一个时,则通过instantiate方法实例化bean,然后注入到BeanWrapperImpl中,直接返回。

instantiate方法会在后面进行分析。

#2.4 当上述分支都不满足,则走如下分支:通过提取配置文件中的信息来执行构建操作(代码还是有些长,分段来看):

           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();
// 解析构造函数参数
// 将bean的构造函数解析为resolvedValues对象,其中会涉及到其他的bean
minNrOfArgs = resolveConstructorArguments(beanName, mbd, bw, cargs, resolvedValues);
} else {
minNrOfArgs = 0;
}
}

分析:

  • 首先对工厂方法进行排序处理,排序规则:public工厂方法优先,参数数量降序,然后非public工厂方法优先,参数数量降序。
  • 如果入参中带有构造参数,则直接获取构造参数的个数。
  • 否则需从BeanDefinition中获取构造函数,并进行解析。xml配置文件的构造函数解析在加载BeanDefinition的过程中有提及。
  • 然后通过resolveConstructorArguments解析构造函数,并返回构造参数的最小个数。resolveConstructorArguments函数目前这里不做分析。

#2.4.1 上步中确定了构造参数,接下来进行构造函数的确定:

           // 遍历candidates
for (Method candidate : candidates) {
// 方法体参数
Class<?>[] paramTypes = candidate.getParameterTypes(); if (paramTypes.length >= minNrOfArgs) {
// 保存参数对象
ArgumentsHolder argsHolder;
// getBean()传递了参数
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用于解析方法和构造函数的参数名,为参数名称探测器
ParameterNameDiscoverer pnd = this.beanFactory.getParameterNameDiscoverer();
// 获取指定构造函数的参数名
if (pnd != null) {
paramNames = pnd.getParameterNames(candidate);
}
// 在已解析构造函数参数值的情况下,创建一个参数持有者ArgumentsHolder对象
argsHolder = createArgumentArray(beanName, mbd, resolvedValues, bw,
paramTypes, paramNames, candidate, autowiring, candidates.length == 1);
} 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<>();
}
// 发生UnsatisfiedDependencyException异常,添加到causes中
causes.add(ex);
continue;
}
} // isLenientConstructorResolution判断解析构造函数的时候是否以宽松模式还是严格模式
// 宽松模式:使用具有"最接近的模式"进行匹配
// 严格模式:解析构造函数时,必须所有的都需要匹配,否则抛出异常
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);
}
}
}

分析:

  • 遍历所有构造函数。
  • 如果方法体参数大于等于最小参数个数,则判断是否传入了构造参数,如果是,则根据入参创建参数持有者对象ArgumentsHolder;否则通过方法体获取指定构造函数的参数,并创建参数持有者对象ArgumentsHolder。
  • 接着确定构造函数的解析是使用宽松模式还是严格模式。
  • 严格模式:解析构造函数时,必须所有参数都需要匹配,否则抛出异常。
  • 宽松模式:使用具有”最接近的模式”进行匹配。

#3.在参数与工厂构造函数确认好后,就可以进行bean的实例化了

 // 没有可执行的工厂方法,则抛出异常
if (factoryMethodToUse == null || argsToUse == 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) {
mbd.factoryMethodToIntrospect = factoryMethodToUse;
argsHolderToUse.storeCache(mbd, factoryMethodToUse);
}
} // 创建bean对象,并设置到BeanWrapperImpl中
bw.setBeanInstance(instantiate(beanName, mbd, factoryBean, factoryMethodToUse, argsToUse));
return bw;

分析:

  • 如果工厂方法为空或构造参数为空,经过一系列异常判断后,最后会将解析的构造函数加入缓存。
  • 然后通过instantiate方法创建bean对象,并注入到BeanWrapperImpl中,最后返回bw。
 // ConstructorResolver

     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;
}
}
} // RootBeanDefinition.java
/**
* 构造函数的缓存锁
* Common lock for the four constructor fields below.
*/
final Object constructorArgumentLock = new Object(); /**
* 缓存已经解析的构造函数或工厂方法<br/>
* Package-visible field for caching the resolved constructor or factory method.
*/
@Nullable
Executable resolvedConstructorOrFactoryMethod; /**
* 标记字段:标记构造函数、参数是否已经解析,默认为false<br/>
* Package-visible field that marks the constructor arguments as resolved.
*/
boolean constructorArgumentsResolved = false; /**
* 缓存已经解析的构造函数参数,包括可见字段<br/>
* Package-visible field for caching fully resolved constructor arguments.
*/
@Nullable
Object[] resolvedConstructorArguments;

分析:

这里就是将构造函数、构造参数进行缓存,也就是最开始为什么要从缓存中获取的原因。

ConstructorResolver#instantiate

 private Object instantiate(String beanName, RootBeanDefinition mbd,
@Nullable Object factoryBean, Method factoryMethod, Object[] args) { try { if (System.getSecurityManager() != null) {
return AccessController.doPrivileged((PrivilegedAction<Object>) () ->
this.beanFactory.getInstantiationStrategy().instantiate(
mbd, beanName, this.beanFactory, factoryBean, factoryMethod, args),
this.beanFactory.getAccessControlContext());
} else {
return this.beanFactory.getInstantiationStrategy().instantiate(
mbd, beanName, this.beanFactory, factoryBean, factoryMethod, args);
}
} catch (Throwable ex) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Bean instantiation via factory method failed", ex);
}
}

分析:

该方法就是创建bean对象的方法,这里会委托调用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对象 通过反射执行工厂方法并返回创建的bean对象
Object result = factoryMethod.invoke(factoryBean, args);
// 未创建,则创建NullBean对象
if (result == null) {
result = new NullBean();
}
return result;
} finally {
// 设置老的method对象到currentlyInvokedFactoryMethod中
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());
}
}

分析:

  • 首先设置方法的可访问性。
  • 然后更新currentlyInvokedFactoryMethod缓存的方法。
  • 核心点是通过反射执行工厂方法创建bean对象。
  • 最后再次更新currentlyInvokedFactoryMethod。

至此通过工厂方法实例化Bean对象的过程分析完毕,真的是不容易,当然文中还有些方法未详细分析,后续再进行查漏补缺。

总结

instantiateUsingFactoryMethod方法体很大,但是其核心点就是确定工厂对象,获取构造函数和构造参数,最后通过SimpleInstantiationStrategy#instantiate反射执行工厂方法创建bean对象。


by Shawn Chen,2019.04.24日,下午。

【spring源码分析】IOC容器初始化(九)的更多相关文章

  1. SPRING源码分析:IOC容器

    在Spring中,最基本的IOC容器接口是BeanFactory - 这个接口为具体的IOC容器的实现作了最基本的功能规定 - 不管怎么着,作为IOC容器,这些接口你必须要满足应用程序的最基本要求: ...

  2. Spring源码解析-ioc容器的设计

    Spring源码解析-ioc容器的设计 1 IoC容器系列的设计:BeanFactory和ApplicatioContext 在Spring容器中,主要分为两个主要的容器系列,一个是实现BeanFac ...

  3. spring源码分析---IOC(1)

    我们都知道spring有2个最重要的概念,IOC(控制反转)和AOP(依赖注入).今天我就分享一下spring源码的IOC. IOC的定义:直观的来说,就是由spring来负责控制对象的生命周期和对象 ...

  4. spring 源码之 ioc 容器的初始化和注入简图

    IoC最核心就是两个过程:IoC容器初始化和IoC依赖注入,下面通过简单的图示来表述其中的关键过程:

  5. Spring源码阅读-IoC容器解析

    目录 Spring IoC容器 ApplicationContext设计解析 BeanFactory ListableBeanFactory HierarchicalBeanFactory Messa ...

  6. Spring 源码剖析IOC容器(一)概览

    目录 一.容器概述 二.核心类源码解读 三.模拟容器获取Bean ======================= 一.容器概述 spring IOC控制反转,又称为DI依赖注入:大体是先初始化bean ...

  7. Spring源码解析-IOC容器的实现

    1.IOC容器是什么? IOC(Inversion of Control)控制反转:本来是由应用程序管理的对象之间的依赖关系,现在交给了容器管理,这就叫控制反转,即交给了IOC容器,Spring的IO ...

  8. Spring源码解析-IOC容器的实现-ApplicationContext

    上面我们已经知道了IOC的建立的基本步骤了,我们就可以用编码的方式和IOC容器进行建立过程了.其实Spring已经为我们提供了很多实现,想必上面的简单扩展,如XMLBeanFacroty等.我们一般是 ...

  9. Spring源码之IOC容器创建、BeanDefinition加载和注册和IOC容器依赖注入

    总结 在SpringApplication#createApplicationContext()执行时创建IOC容器,默认DefaultListableBeanFactory 在AbstractApp ...

  10. 【spring源码分析】IOC容器初始化(总结)

    前言:在经过前面十二篇文章的分析,对bean的加载流程大致梳理清楚了.因为内容过多,因此需要进行一个小总结. 经过前面十二篇文章的漫长分析,终于将xml配置文件中的bean,转换成我们实际所需要的真正 ...

随机推荐

  1. 当心Azure跨区域数据传输产生额外费用

    最近同事发现Azure上一台虚拟机的费用环比增加了一部分.后面仔细检查发现费用来自数据传输, 因为这是早期部署的一台Azure虚拟机(Iaas),我们在本地生成备份,然后通过AzCopy到存储账号的B ...

  2. SQLServer之修改用户自定义数据库用户

    修改用户自定义数据库用户注意事项 默认架构将是服务器为此数据库用户解析对象名时将搜索的第一个架构. 除非另外指定,否则默认架构将是此数据库用户创建的对象所属的架构. 如果用户具有默认架构,则将使用默认 ...

  3. 计算器模拟器中的情怀——Free42简介

    说到情怀,我首先想聊几句电子计算器的历史.电子计算器这种东西,在最近这几十年的人类发展中,曾经起到过相当重要的作用,尤其是在七十年代到九十年代初这个时期,大型的全功能电脑贵得要命,有钱有时也买不到,而 ...

  4. JVM内存结构/JVM运行时数据区,以及堆内存的划分

    1.程序计数器: 程序计数器是线程私有的内存,JVM多线程是通过线程轮流切换并分配处理器执行时间的方式实现的,当线程切换后需要恢复到正确的执 行位置(处理器)时,就是通过程序计数器来实现的.此内存区域 ...

  5. java日志框架log4j详细配置及与slf4j联合使用教程

    最后更新于2017年02月09日 一.log4j基本用法 首先,配置log4j的jar,maven工程配置以下依赖,非maven工程从maven仓库下载jar添加到“build path” <d ...

  6. Android 音视频开发学习思路

    Android 音视频开发这块目前的确没有比较系统的教程或者书籍,网上的博客文章也都是比较零散的.只能通过一点点的学习和积累把这块的知识串联积累起来. 初级入门篇: Android 音视频开发(一) ...

  7. Linux 使用 free 命令查看内存使用情况

    1.free 命令的选项 使用 free 命令查看服务器内存使用情况. free [-b|-k|-m|-g|-h] [-l] [-o] [-t] [-s delay] [-c count] [-V] ...

  8. [Swift-2019力扣杯春季决赛]4. 有效子数组的数目

    给定一个整数数组 A,返回满足下面条件的 非空.连续 子数组的数目: 子数组中,最左侧的元素不大于其他元素. 示例 1: 输入:[1,4,2,5,3] 输出:11 解释:有 11 个有效子数组,分别是 ...

  9. 学习pwn的前提工作及部分解决方案

    一.Ubuntu 在VM安装64位的Ubuntu 二.pwntools 基本语法 sudo apt-get install libffi-dev sudo apt-get install libssl ...

  10. 自写脚本实现上线前本地批量压缩混淆 js , css 代码。

    最近做项目遇到一个要求,就是把本地的 js 和 css 进行压缩后再上线,由于之前项目并没有使用 webpack 之类的库,项目上也因为一些机密不能在线上压缩,这无疑给代码打包压缩带来了很大麻烦,于是 ...