前言
上文在分析IOC中getBean方法
讲到getBean的整个调用逻辑是:
doGetBean-->getSingleton-->createBean-->createBeanInstance。
是一个获取不到就创建的逻辑(Lazy load)。
而createBeanInstance创建createBean,使用三种策略之一:
- factory method, 工厂方法
- constructor autowiring,构造方式自动注入
- simple instantiation,通过无参数构造方法,另外bean的信息配置了lookup-method和replace-method会另外处理。返回类型是BeanWrapper,能用于填充对象的属性
本文就重点介绍autowireConstructor的过程。
autowireConstructor
createBeanInstance的代码通过不同的条件选择调用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
ConstructorResolver类通过参数匹配方式来进行构造,是一种策略模式。调用的方法autowireConstructor用于生成需要的BeanWrapper(Bean的一个包装类,用于获取bean的一些属性)。
方法入参数
- beanName: bean的名称
- mbd:merged bean definition
- chosenCtors:选择的构造器
- explicitArgs:getBean方法中传入的参数,如果是none,则使用bean定义中的构造器参数。
源码和源码的解读(注释中)如下:
public BeanWrapper autowireConstructor(String beanName, RootBeanDefinition mbd,
@Nullable Constructor[] chosenCtors, @Nullable Object[] explicitArgs) {
// beanwrapper的默认实现
BeanWrapperImpl bw = new BeanWrapperImpl();
this.beanFactory.initBeanWrapper(bw);
Constructor constructorToUse = null;
ArgumentsHolder argsHolderToUse = null;
Object[] argsToUse = null;
// 参数处理
if (explicitArgs != null) {
argsToUse = explicitArgs;
}
else {
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) {
argsToResolve = mbd.preparedConstructorArguments;
}
}
}
if (argsToResolve != null) {
argsToUse = resolvePreparedArguments(beanName, mbd, bw, constructorToUse, argsToResolve, true);
}
}
if (constructorToUse == null || argsToUse == null) {
// 获取构造方法列表
Constructor[] candidates = chosenCtors;
if (candidates == null) {
Class beanClass = mbd.getBeanClass();
try {
// public, protected, default (package) access, and private constructors
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 到 non-public降序
// 多参数到少参数 降序
AutowireUtils.sortConstructors(candidates);
int minTypeDiffWeight = Integer.MAX_VALUE;
Set> ambiguousConstructors = null;
LinkedList causes = null;
for (Constructor candidate : candidates) {
Class[] paramTypes = candidate.getParameterTypes();
if (constructorToUse != null && argsToUse != null && argsToUse.length > paramTypes.length) {
// 找到了满足条件的构造函数,提前结束循环
// argsToUse.length > paramTypes.length这个是怎么来的呢?首先前面是排序过的,如果有多个构造函数能满足,优先选择到public和参数多的。参数少的,和权限低的就不用选择了。
// 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 {
// 判断否则方法是否有 ConstructorProperties 注解,若有,则取注解中的
String[] paramNames = ConstructorPropertiesChecker.evaluate(candidate, paramTypes.length);
if (paramNames == null) {
ParameterNameDiscoverer pnd = this.beanFactory.getParameterNameDiscoverer();
if (pnd != null) {
// 获取构造参数的名称,public fun(String a, int b),返回的就是[a, b]
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 (paramTypes.length != explicitArgs.length) {
continue;
}
argsHolder = new ArgumentsHolder(explicitArgs);
}
// 计算每个参数类型与构造方法参数列表的差异,差异小的,说明是合适的构造方法
// 这里typeDiffWeight可以看作一个相似度的度量
// mbd.isLenientConstructorResolution() 条件。官方的解释是:返回构造方法的解析模式,有宽松模式(lenient mode)和严格模式(strict mode)两种类型可选。这两个类型的区别是什么,暂时不去考虑,以后有时间再看吧。todo
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;
}
// 以上条件都无法选择出最好的构造方法,就放入ambiguousConstructors这个中,下面一个逻辑是说如果这个ambiguousConstructors不为空直接抛出异常,看来spring不会给出默认选择项啊,对于编程语言来说,严格更不容易出现莫名其妙的错,这样其实是很好的。
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");
// instantiate最终创建了bean,默认是反射模式,如果包含 lookup-method 和 replace-method,则通过 CGLIB 增强 bean 实例
bw.setBeanInstance(instantiate(beanName, mbd, constructorToUse, argsToUse));
return bw;
}
小结
- 创建 BeanWrapperImpl 对象
- 构造候选方法只有一个的情况,满足就构造
- 构造候选方法多个的情况,获取构造方法和参数列表,并排序
排序规则是,优先public和参数多的 - 如果有个public而且参数多于需要的参数,选之
- 其次,选择参数相等的,参数不足的直接忽略
- 参数相等的情况,做类型转化,计算一个typeDiffWeight,相似参数的度量,选择最相似的,如果多个typeDiffWeight相等,那么报错。
- 最后调用instantiate生成beanInstance的Object放到包装类BeanWrapper中,返回BeanWrapper
instantiate
看完上面的小结,知道beanInstance的核心逻辑在instantiate
这个方法如下:
private Object instantiate(
String beanName, RootBeanDefinition mbd, Constructor constructorToUse, Object[] argsToUse) {
try {
InstantiationStrategy strategy = this.beanFactory.getInstantiationStrategy();
if (System.getSecurityManager() != null) {
return AccessController.doPrivileged((PrivilegedAction
核心逻辑是:
InstantiationStrategy strategy = this.beanFactory.getInstantiationStrategy();
return strategy.instantiate(mbd, beanName, this.beanFactory, constructorToUse, argsToUse);
通过策略模式,调用instantiate生成Object
spring中这个策略模式有个一个简单实现,在SimpleInstantiationStrategy中。代码如下:
@Override
public Object instantiate(RootBeanDefinition bd, @Nullable String beanName, BeanFactory owner,
final Constructor ctor, Object... args) {
if (!bd.hasMethodOverrides()) {
if (System.getSecurityManager() != null) {
// use own privileged to change accessibility (when security is on)
AccessController.doPrivileged((PrivilegedAction
其中return地方有两处:
- return instantiateWithMethodInjection(bd, beanName, owner, ctor, args);
这个使用 GCLIG 创建 bean 对象,这个暂时不看,以后有机会再看。 - return BeanUtils.instantiateClass(ctor, args);
这个是更普遍使用的创建bean的逻辑。下面重点阅读
BeanUtils.instantiateClass
看到这里,已经几乎是最底层的bean生成的逻辑,仿佛一个俄罗斯套娃,一层层拨开逻辑终于到了最内核的这部分。
public static T instantiateClass(Constructor ctor, Object... args) throws BeanInstantiationException {
Assert.notNull(ctor, "Constructor must not be null");
try {
ReflectionUtils.makeAccessible(ctor);
return (KotlinDetector.isKotlinReflectPresent() && KotlinDetector.isKotlinType(ctor.getDeclaringClass()) ?
KotlinDelegate.instantiateClass(ctor, args) : ctor.newInstance(args));
}
catch (InstantiationException ex) {
throw new BeanInstantiationException(ctor, "Is it an abstract class?", ex);
}
catch (IllegalAccessException ex) {
throw new BeanInstantiationException(ctor, "Is the constructor accessible?", ex);
}
catch (IllegalArgumentException ex) {
throw new BeanInstantiationException(ctor, "Illegal arguments for constructor", ex);
}
catch (InvocationTargetException ex) {
throw new BeanInstantiationException(ctor, "Constructor threw exception", ex.getTargetException());
}
}
其中:KotlinDelegate.instantiateClass(ctor, args)是Kotlin primary constructor,这个类这里先不介绍,以后有时间看。
更普遍的调用逻辑是:
ReflectionUtils.makeAccessible(ctor); // 这个ReflectionUtils是反射工具类
ctor.newInstance(args)