Spring中bean虽然可以通过多种方式(Supplier接口、FactoryMethod、构造器)创建bean的实例对象,但是使用最多的还是通过构造器创建对象实例,也是我们最熟悉的创建对象的方式。如果有多个构造器时,那Spring是如何推断使用哪个构造器来创建bean对象实例的?
一、Spring中创建对象实例的方式
(1) 通过构造器实例化对象
这是我们创建实例最常使用的方式,也是最常见的方式。
java
public class ObjectInstance {
private String createMode;
public ObjectInstance(String createMode) {
System.out.println("create by constructor");
this.createMode = createMode;
}
public ObjectInstance() {
}
public String getCreateMode() {
return createMode;
}
public void setCreateMode(String createMode) {
this.createMode = createMode;
}
@Override
public String toString() {
return "ObjectInstance{" +
"createMode='" + createMode + '\'' +
'}';
}
}
java
<!--通过构造器实例化bean-->
<bean id="objBean" class="cn.crazy.newInstance.ObjectInstance">
<constructor-arg name="createMode" value="create by constructor"></constructor-arg>
</bean>
(2)通过工厂方法实例化对象
java
public class CrazyInstanceFactory {
//静态工厂方法
public static Object newInstanceForStatic(){
ObjectInstance objectInstance = new ObjectInstance();
objectInstance.setCreateMode("create by factory's static method");
return objectInstance;
}
//实例工厂方法
public Object newInstance(){
ObjectInstance objectInstance = new ObjectInstance();
objectInstance.setCreateMode("create by factory's instance method");
return objectInstance;
}
}
(i)静态工厂方法
java
<!--通过静态工厂实例化bean-->
<bean id="objInstanceForStaticFactory" class="cn.crazy.newInstance.CrazyInstanceFactory" factory-method="newInstanceForStatic"></bean>
(ii)实例工厂方法
java
<!--通过实例工厂实例化bean-->
<bean id="crazyInstanceFactory" class="cn.crazy.newInstance.CrazyInstanceFactory"></bean>
<bean id="objInstance" factory-bean="crazyInstanceFactory" factory-method="newInstance"></bean>
(3)通过实现FactoryBean接口实例化对象
java
public class CrazyFactoryBean implements FactoryBean<ObjectInstance> {
@Override
public ObjectInstance getObject() throws Exception {
ObjectInstance objectInstance = new ObjectInstance();
objectInstance.setCreateMode("create by FactoryBean");
return objectInstance;
}
@Override
public Class<?> getObjectType() {
return null;
}
@Override
public boolean isSingleton() {
return true;
}
}
java
<!--通过FactoryBean接口实例化bean-->
<bean id="objInstanceForFactoryBean" class="cn.crazy.newInstance.CrazyFactoryBean"></bean>
(4)通过Supplier实例化对象
java
public class SupplierObj{
private String version;
private int num;
public SupplierObj() {
}
public String getVersion() {
return version;
}
public void setVersion(String version) {
this.version = version;
}
public int getNum() {
return num;
}
public void setNum(int num) {
this.num = num;
}
@Override
public String toString() {
return "SupplierObj{" +
"version='" + version + '\'' +
", num=" + num +
'}';
}
}
使用BeanFactoryPostProcessor对beanDefinition信息进行修改,为其通过一个Supplier,用于实例化bean。
Supplier接口只有一个方法,我们可以用简化语法创建匿名接口实现类。
java
@FunctionalInterface
public interface Supplier<T> {
/**
* Gets a result.
*
* @return a result
*/
T get();
}
java
public class MyPostProcessor implements BeanFactoryPostProcessor {
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
GenericBeanDefinition beanDefinition = (GenericBeanDefinition)beanFactory.getBeanDefinition("supplierObj");
//beanDefinition.getConstructorArgumentValues().addIndexedArgumentValue();
beanDefinition.setInstanceSupplier(() -> {
SupplierObj supplierObj1 = new SupplierObj();
return supplierObj1;
});
}
}
java
<bean id="supplierObj" class="cn.crazy.newInstance.SupplierObj">
<property name="num" value="12"></property>
<property name="version" value="1.0.0"></property>
</bean>
二、推断构造器
(1)doCreateBean(),创建bean实例对象。
doCreateBean()方法是Spring进行Bean创建的核心方法,它包含三个参数:
- String beanName,就是bean的id或anme;
- RootBeanDefinition mbd,Spring Bean在没有被创建之前,bean的信息(xml配置bean及注解注入的信息)会被解析成BeanDefinition对象,我们知道Class是描述Java对象信息的,那么BeanDefinition就是描述Spring Bean信息的;
- Object[] args,构造器参数。这个值默认为null,除非程序员自己调用api传入参数。
这个方法中会调用多次后置处理器,用于推断构造器、完成BD合并、解决循环依赖、解析注解等。我们今天主要看关于自动装配相关的内容,所以给这个方法省略了一些内容。
首先是推断构造器,通过合适的构造器创建bean的实例,然后对实例进行属性填充。
java
protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
throws BeanCreationException {
// Instantiate the bean.
BeanWrapper instanceWrapper = null;
if (mbd.isSingleton()) {
instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
}
if (instanceWrapper == null) {
//第二次调用后置处理器的入口方法(推断构造方法)
//代码块一:创建实例bean
instanceWrapper = createBeanInstance(beanName, mbd, args);
}
......
//填充属性
//调用第五次和第六次后置处理器的地方
populateBean(beanName, mbd, instanceWrapper);
return exposedObject;
}
(2) createBeanInstance(),根据特定的bean及实例化策略创建一个bean实例。
实例化一个bean的方式包括Supplier接口、FactoryMethod、构造器等。
spring会缓存一些关于对象创建中比较复杂的操作,方便在原型下bean创建可以直接获取到对象创建的方式,而不是又进行复杂的推断。
resolved表示创建对象的构造方法有没有被解析过 。为什么要有这个标签?
方便spring快速的创建对象 ,因为创建对象时,推断构造方法是个很复杂的过程,在创建原型bean时,可以只推断一次,后续不用在执行这个复杂的操作 。
java
protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) {
// Make sure bean class is actually resolved at this point.
Class<?> beanClass = resolveBeanClass(mbd, beanName);
//判断beanClass是否不符合要求
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());
}
//这段代码的含义是?spring提供了一个Supplier接口,用于实例化bean
Supplier<?> instanceSupplier = mbd.getInstanceSupplier();
if (instanceSupplier != null) {
return obtainFromSupplier(instanceSupplier, beanName);
}
if (mbd.getFactoryMethodName() != null) {
return instantiateUsingFactoryMethod(beanName, mbd, args);
}
// Shortcut when re-creating the same bean...
//resolved表示创建对象的构造方法有没有被解析过
/**
* 为什么要有这个标签?
* 方便spring快速的创建对象
* 因为创建对象时,推断构造方法是个很复杂的过程,在创建原型bean时,可以只推断一次,后续不用在执行这个复杂的操作
*/
boolean resolved = false;
//构造函数参数是否被解析过
boolean autowireNecessary = false;
//args是goGetBean(......,args,......)的入参,spring自身传入为null
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);
}
}
//推断构造方法,有多个构造方法是,推断出最合适的,如果只有一个构造方法,返回null(不用推断)
// Candidate constructors for autowiring?
//第二次调用后置处理器
//代码块二:推断构造方法
Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);
//如果自动注入的方式为构造器注入,会再一次推断构造方法
if (ctors != null || mbd.getResolvedAutowireMode() == AUTOWIRE_CONSTRUCTOR ||
mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args)) {
//代码三:确定构造方法参数的值
return autowireConstructor(beanName, mbd, ctors, args);
}
// Preferred constructors for default construction?
ctors = mbd.getPreferredConstructors();
if (ctors != null) {
return autowireConstructor(beanName, mbd, ctors, null);
}
// No special handling: simply use no-arg constructor.
return instantiateBean(beanName, mbd);
}
(3)代码块二:determineCandidateConstructors(),推断构造器
推断构造器是通过一个后置处理器AutowiredAnnotationBeanPostProcessor来完成的,这个后置处理器是Spring启动时自添加的。
java
@Override
@Nullable
public Constructor<?>[] determineCandidateConstructors(Class<?> beanClass, final String beanName)
throws BeanCreationException {
// 省略lookup methods检查
//先从缓存中拿,拿不到再进行推断
// Quick check on the concurrent map first, with minimal locking.
Constructor<?>[] candidateConstructors = this.candidateConstructorsCache.get(beanClass);
if (candidateConstructors == null) {
// Fully synchronized resolution now...
synchronized (this.candidateConstructorsCache) {
candidateConstructors = this.candidateConstructorsCache.get(beanClass);
if (candidateConstructors == null) {
Constructor<?>[] rawCandidates;
try {
//getDeclared拿到所有类型的(public、protected、private),但不会拿父类的
//拿到所有的构造器
rawCandidates = beanClass.getDeclaredConstructors();
}
catch (Throwable ex) {
throw new BeanCreationException(beanName,
"Resolution of declared constructors on bean Class [" + beanClass.getName() +
"] from ClassLoader [" + beanClass.getClassLoader() + "] failed", ex);
}
List<Constructor<?>> candidates = new ArrayList<>(rawCandidates.length);
Constructor<?> requiredConstructor = null;
Constructor<?> defaultConstructor = null;
//没有使用到kotlin时永远返回null
Constructor<?> primaryConstructor = BeanUtils.findPrimaryConstructor(beanClass);
int nonSyntheticConstructors = 0;
for (Constructor<?> candidate : rawCandidates) {
if (!candidate.isSynthetic()) {
nonSyntheticConstructors++;
}
else if (primaryConstructor != null) {
continue;
}
MergedAnnotation<?> ann = findAutowiredAnnotation(candidate);
if (ann == null) {
//beanClass是个CGLIB代理类,找到父类
Class<?> userClass = ClassUtils.getUserClass(beanClass);
if (userClass != beanClass) {
try {
Constructor<?> superCtor =
userClass.getDeclaredConstructor(candidate.getParameterTypes());
ann = findAutowiredAnnotation(superCtor);
}
catch (NoSuchMethodException ex) {
// Simply proceed, no equivalent superclass constructor found...
}
}
}
if (ann != null) {
//已经有@Autowired(required=true)标记的构造器时,如果再出现@Autowired标记的构造器时会抛出异常
if (requiredConstructor != null) {
throw new BeanCreationException(beanName,
"Invalid autowire-marked constructor: " + candidate +
". Found constructor with 'required' Autowired annotation already: " +
requiredConstructor);
}
boolean required = determineRequiredStatus(ann);
if (required) {
//有多个加了构造器@Autowired或@Value注解
if (!candidates.isEmpty()) {
throw new BeanCreationException(beanName,
"Invalid autowire-marked constructors: " + candidates +
". Found constructor with 'required' Autowired annotation: " +
candidate);
}
//@Autowired(required=true)的构造器才会设置为requiredConstructor
requiredConstructor = candidate;
}
//只有添加了构造方法上加了@Autowired或@Value注解,该构造方法都会放入candidates
candidates.add(candidate);
}
else if (candidate.getParameterCount() == 0) {
//defaultConstructor设置为无参构造器
defaultConstructor = candidate;
}
}
if (!candidates.isEmpty()) {
// Add default constructor to list of optional constructors, as fallback.
if (requiredConstructor == null) {
if (defaultConstructor != null) {
//如果candidates不能空,且无确定的构造方法,添加默认的构造方法到可选列表中
candidates.add(defaultConstructor);
}
else if (candidates.size() == 1 && logger.isInfoEnabled()) {
logger.info("Inconsistent constructor declaration on bean with name '" + beanName +
"': single autowire-marked constructor flagged as optional - " +
"this constructor is effectively required since there is no " +
"default constructor to fall back to: " + candidates.get(0));
}
}
//将candidates转换为构造器数组
candidateConstructors = candidates.toArray(new Constructor<?>[0]);
}
//仅当一个有参构造方法时,才会返回这个构造方法
else if (rawCandidates.length == 1 && rawCandidates[0].getParameterCount() > 0) {
candidateConstructors = new Constructor<?>[] {rawCandidates[0]};
}
// primaryConstructor永远为null
else if (nonSyntheticConstructors == 2 && primaryConstructor != null &&
defaultConstructor != null && !primaryConstructor.equals(defaultConstructor)) {
candidateConstructors = new Constructor<?>[] {primaryConstructor, defaultConstructor};
}
else if (nonSyntheticConstructors == 1 && primaryConstructor != null) {
candidateConstructors = new Constructor<?>[] {primaryConstructor};
}
else {
//空构造器数组
candidateConstructors = new Constructor<?>[0];
}
this.candidateConstructorsCache.put(beanClass, candidateConstructors);
}
}
}
return (candidateConstructors.length > 0 ? candidateConstructors : null);
}
这个方法大致总结为:
1)先从缓存中获取候选构造器数组, 如果能获取成功,判断数组长度是否大于0,大于0则返回这个构造器数组,否则返回null。不存在缓存则进行步骤2。
2)获取beanClass中的所有类型的构造器(public、protected、private),存放到rawCandidates数组。创建一个存放候选构造器的List集合candidates,长度为 rawCandidates数组的长度,创建三个构造器类型的变量requiredConstructor(存储@Autowired(required = true)标记的构造器)、defaultConstructor(存储默认的构造器)和primaryConstructor(没有使用到kotlin时永远返回null
),创建一个int类型的变量nonSyntheticConstructors,用于记录beanClass非合成构造器的个数。
3)遍历rawCandidates数组,如果当前的构造器对象为非合成构造器nonSyntheticConstructors计数器+1。定义一个MergedAnnotation类型变量ann,存放当前构造器的Autowired注解信息,如果当前beanClass的ann为null,判断beanClass是否为CGLIB代理类,如果是,将父类相同(参数类型相同)构造器上的Autowired注解信息赋值给ann。
(a)如果注解信息ann不为null
(i)判断requiredConstructor是否为null,如果不为null,说明beanClass中已经存在一个@Autowired(required=true)的构造器,抛出异常!
(ii)获取当前构造器上的注解信息ann的required属性值,如果为true,如果候选构造器的List集合candidates不为空,抛出异常。否则将当前构造器赋值给requiredConstructor变量。
(iii)将当前构造器加入到候选构造器的List集合candidates中。
(b) 如果注解信息ann为null
如果当前构造器为无参构造器,将当前构造器赋值给defaultConstructor变量。
4)完成遍历后,有如下几种情况
(a)candidates不为空的情况,如果requiredConstructor为null,defaultConstructor不为null,将defaultConstructor加入候选构造器集合candidates中。将candidates转换为构造器数组对象。
(b)rawCandidates数组长度为1且其中的构造器参数个数大于0(仅当一个有参构造方法时,才会返回这个构造方法),将这个构造器对象封装成构造器数组对象。
(c)nonSyntheticConstructors==2(beanClass只有两个非合成构造器)且primaryConstructor不为null(没有使用到kotlin时永远返回null),将primaryConstructor和defaultConstructor封装成构造器数组对象。
(d)nonSyntheticConstructors==1且primaryConstructor不为null(没有使用到kotlin时永远返回null),将primaryConstructorr封装成构造器数组对象。
(e)不是以上情况,返回空构造器数组对象。
5)将构造器数组对象缓存到spring容器中,并返回这个数组对象。
(3)代码块三:autowireConstructor(),确定构造器及构造器方法参数的值,完成对象实例化。
通过推断构造器方法只是推断出合适的构造器,但是可能存在多个候选构造器的情况,而且构造器的参数值也还没有确定,接下来就是确定构造方法参数的值,并完成对象的实例化。
java
{
......
Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);
//如果自动注入的方式为构造器注入,会再一次推断构造方法
if (ctors != null || mbd.getResolvedAutowireMode() == AUTOWIRE_CONSTRUCTOR ||
mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args)) {
//确定构造方法参数的值
return autowireConstructor(beanName, mbd, ctors, args);
}
......
}
protected BeanWrapper autowireConstructor(
String beanName, RootBeanDefinition mbd, @Nullable Constructor<?>[] ctors, @Nullable Object[] explicitArgs) {
return new ConstructorResolver(this).autowireConstructor(beanName, mbd, ctors, explicitArgs);
}
//这里只是简单初始化
public ConstructorResolver(AbstractAutowireCapableBeanFactory beanFactory) {
this.beanFactory = beanFactory;
this.logger = beanFactory.getLogger();
}
这里定义了很多中间变量,如:
//最终使用的构造方法
Constructor<?> constructorToUse = null;
//最终使用的参数持有者,维护了参数差异值比较的方法
ArgumentsHolder argsHolderToUse = null;
//最终使用的构造方法参数
Object[] argsToUse = null;
//这个值默认为null,除非程序员自己调用api传入参数
//createBean(beanName, mbd, args);中args即是explicitArgs
Object[] explicitArgs;
//解析出来的构造器参数值
//解析出来的参数不一定就是可以直接注入的属性,需要进行转换
//如<constructor-arg type="" ></constructor-arg>或如<constructor-arg ref="" ></constructor-arg>
//需要转换成具体的Bean才能注入
Object[] argsToResolve = null;
//最小参数个数,如果手动设置构造器参数,createBean(beanName, mbd, args)或
//xml配置了<constructor-arg></constructor-arg>
//或设置了BeanDefinition.getConstructorArgumentValues().addArgumentValues();
//最小参数个数就是设置参数的个数
int minNrOfArgs;
java
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;
//构造器参数。这个值默认为null,除非程序员自己调用api传入参数
//createBean(beanName, mbd, args);中args即是explicitArgs
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) {
//构造器中没有缓存构造参数,就需要获取preparedConstructorArguments
//部分准备好的构造函数参数,不是最终使用的构造器参数,需要转换
argsToResolve = mbd.preparedConstructorArguments;
}
}
}
if (argsToResolve != null) {
//解析出来的参数不一定就是可以直接注入的属性,需要进行转换
//如<constructor-arg type="" ></constructor-arg>或如<constructor-arg ref="" ></constructor-arg>
//需要转换成具体的Bean才能注入
argsToUse = resolvePreparedArguments(beanName, mbd, bw, constructorToUse, argsToResolve, true);
}
}
if (constructorToUse == null || argsToUse == null) {
// Take specified constructors, if any.
Constructor<?>[] candidates = chosenCtors;
if (candidates == null) {
Class<?> beanClass = mbd.getBeanClass();
try {
//拿出所有的构造方法
// mbd.isNonPublicAccessAllowed() == true,是否允许非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;
}
//通过无参构造器实例化bean
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;
//实际传入构造方法参数个数不为null
if (explicitArgs != null) {
//如果指定了构造器参数值,最小参数个数为指定的参数个数
minNrOfArgs = explicitArgs.length;
}
else {
//xml配置了<constructor-arg></constructor-arg>
//或设置了BeanDefinition.getConstructorArgumentValues().addArgumentValues();
//就根据手动设置的构造器参数推断出所需要的构造器
ConstructorArgumentValues cargs = mbd.getConstructorArgumentValues();
resolvedValues = new ConstructorArgumentValues();
//找出构造方法的参数个数,并根据cargs构建ConstructorArgumentValues对象
minNrOfArgs = resolveConstructorArguments(beanName, mbd, bw, cargs, resolvedValues);
}
//代码块四:对candidates进行排序
AutowireUtils.sortConstructors(candidates);
//计算权重
int minTypeDiffWeight = Integer.MAX_VALUE;
//存放摸棱两可的构造器
Set<Constructor<?>> ambiguousConstructors = null;
Deque<UnsatisfiedDependencyException> causes = null;
for (Constructor<?> candidate : candidates) {
int parameterCount = candidate.getParameterCount();
//因为进行了排序,如果当前的parameterCount<argsToUse.length,那么后续candidate.parameterCount总是小于argsToUse.length
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
//这个方法是遍历构造器的参数名字和参数类型,找到与之匹配的resolvedValues中的ValueHolder值,并封装成ArgumentsHolder对象
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 ArrayDeque<>(1);
}
causes.add(ex);
continue;
}
}
else {
// Explicit arguments given -> arguments length must match exactly.
if (parameterCount != explicitArgs.length) {
continue;
}
argsHolder = new ArgumentsHolder(explicitArgs);
}
//计算差异值,当多个构造方法的参数个数相同时,通过差异值决定使用哪个构造方法
//mbd.isLenientConstructorResolution()是否为宽松模式,默认是宽松模式
int typeDiffWeight = (mbd.isLenientConstructorResolution() ?
argsHolder.getTypeDifferenceWeight(paramTypes) : argsHolder.getAssignabilityWeight(paramTypes));
// Choose this constructor if it represents the closest match.
//如果当前构造器的差异值比minTypeDiffWeight小,将当前构造器的差异值赋值给minTypeDiffWeight变量
if (typeDiffWeight < minTypeDiffWeight) {
//最终使用的构造器constructorToUse赋值为当前构造器
constructorToUse = candidate;
//最终使用的参数持有者argsHolderToUse赋值为当前的argsHolder
argsHolderToUse = argsHolder;
//最终使用的构造器参数argsToUse赋值为当前的argsHolder的arguments
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);
}
}
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) {
//代码块五:将推断出来的构造方法信息缓存到BD中
argsHolderToUse.storeCache(mbd, constructorToUse);
}
}
Assert.state(argsToUse != null, "Unresolved constructor arguments");
//根据推断出来的构造器及其参数创建bean实例,并封装到bw对象中
bw.setBeanInstance(instantiate(beanName, mbd, constructorToUse, argsToUse));
return bw;
}
这个方法大致总结为:
1)先后bd缓存中获取构造函数的相关信息(构造器、构造参数),如果缓存是部分准备好的构造函数参数,需要转换成最终可使用的构造参数。
2)缓存中获取构造器或构造参数失败,有如下两种情况:
a.通过determineCandidateConstructors()推断出来的构造器不为null,直接将推断出来的构造器存放到构造器数组candidates。
b.通过determineCandidateConstructors()推断出来的构造器为null,拿到当前beanClass中的所有构造器,存放到构造器数组candidates。
3)如果candidates中只有一个构造器且为无参构造,将该构造器信息缓存到bd中,同时通过这个无参构造器创建bean实例对象,并封装到BeanWrapperImpl中返回。
4)设置构造器最小参数值minNrOfArgs。如果手动设置了构造器参数,最小参数值就为设置的参数的个数。(通过createBean(beanName, mbd, args)api设置args或者通过xml中<constructor-arg>标签设置。或者是BeanDefinition.getConstructorArgumentValues().addArgumentValues()/BeanDefinition.getConstructorArgumentValues().addIndexedArgumentValue()方式设置)获取bd中的构造参数值,并封装成ConstructorArgumentValues对象(resolvedValues)。
5)对candidates中的构造器进行排序。创建构造器差异值变量minTypeDiffWeight,并将其赋值为Integer.MAX_VALUE(构造器差异值最小的即为最优解);创建 ambiguousConstructors 变量用于存放模棱两可的构造器。
6)遍历candidates,获取当前构造器的参数个数parameterCount,如果上一个回合已经推断出constructorToUse和argsToUse,且argsToUse的长度大于当前构造器的参数个数,直接退出遍历。(因为进行了排序,如果当前的parameterCount<argsToUse.length,那么后续candidate.parameterCount可能总是小于argsToUse.length,虽然可能存在修饰符不同的情况,但是这里排序修饰符比构造参数个数优先级高)。在遍历的代码块中有一个重要的逻辑就是计算差异值,而计算差异值的前提是两个构造器的构造参数个数相同。如果当前构造器比前一个构造器的构造参数个数少,是没有资格进行差异值比较的。
7)如果当前构造器的个数parameterCount 小于最小构造器参数个数minNrOfArgs,跳过本次循环,进行下次循环(pubulic修饰的构造器不满足,可能protected或private修饰的构造器满足)。
8)构建参数持有者ArgumentsHolder argsHolder,获取当前构造器的构造器参数类型数组Class<?>[] paramTypes。
(i)resolvedValues值不为空。获取当前构造器参数名字数组。遍历构造器的参数名字和参数类型数组,找到与之匹配的resolvedValues中的ValueHolder值,并封装成ArgumentsHolder对象。
(ii)explicitArgs不为空,直接通过explicitArgs构建ArgumentsHolder对象。
9)计算差异值,当多个构造方法的参数个数相同时,通过差异值决定使用哪个构造方法。
(i)如果当前构造器的差异值比minTypeDiffWeight小,将当前构造器的差异值赋值给minTypeDiffWeight变量,并把最终使用的构造器constructorToUse赋值为当前构造器 constructorToUse = candidate; 最终使用的参数持有者argsHolderToUse赋值为当前的argsHolder argsHolderToUse = argsHolder; 最终使用的构造器参数argsToUse赋值为当前的argsHolder的arguments。同时将ambiguousConstructors值设置为null.
(ii) 如果当前构造器的差异值与minTypeDiffWeig相等,就会将它放入ambiguousConstructors(如果为null,先创建ambiguousConstructors)中。
10)如果存在模棱两可的构造器且不是宽松模式下,抛出异常。严格模式下,spring认为不能存在摸棱两可的构造器,而且宽松模式和严格模式下差异值计算的算法也不一样。spring默认为宽松模式。
11)将推断出来的构造方法信息缓存到BD中,并根据推断出来的构造器及其参数创建bean实例,并封装到bw对象中返回。
(i)代码块四:构造器排序规则
构造器的排序规则。public修饰的构造器排在前面,如果同为public类型,比较构造器的参数个数,参数个数多的排在前面。
java
public static final Comparator<Executable> EXECUTABLE_COMPARATOR = (e1, e2) -> {
int result = Boolean.compare(Modifier.isPublic(e2.getModifiers()), Modifier.isPublic(e1.getModifiers()));
//为什么在自动注入方式为构造方法注入时,会选择构造方法参数比较多的那个构造方法
return result != 0 ? result : Integer.compare(e2.getParameterCount(), e1.getParameterCount());
};
(ii)代码块五:storeCache(),将推断出来的构造方法信息缓存到BD中
java
//将推断出来的构造方法信息缓存到BD中
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;
}
}
}
}
三、总结
spring推断构造方法分如下几种情况:
(1)不使用自动装配时。
1)无构造方法或只有一个无参构造方法的情况下,返回null
2)有且只有一个有参构造方法时,返回这个有参构造方法
3)有多个构造方法时,返回null
(2)使用@Autowired注入时.
1)如果只有一个构造方法添加了@Autowired(required=true),返回这个构造方法
2)如果有一个构造方法添加了@Autowired(required=true),其他构造方法再添加@Autowired注解,抛出异常
3)如果有多个构造方法添加了@Autowired(required=false),除了返回所以加了@Autowired(required=false)的构造方法,如果提供了无参构造方法,也会返回无参构造方法,后续继续推断构造方法。
(3)使用自动注入时。
根据构造方法的参数类型或参数个数找到最优的构造方法,默认最优的为参数类型为spring中依赖最多,且参数个数最长的那个。