前面说过spring装配bean总体有两种模式,一种是手动装配,一种是自动装配(byName,byType,byContructor)。手动装配是一个bean引用到另外一个的bean情况下,这里我们通常是在xml或注解中手动加入的,但我敢肯定大多数都是用@Autowire注解指定注入bean。自动装配是不需要在代码中通过注解注入(需要set方法)或不需要在xml中配置property,spring就会帮我们做好。回到主题,创建一个对象,需要通过类的指定构造方法来实例化。那我们定义的bean,构造方法可能有多个,那Spring到底是怎样选择构造方法来实例化Bean呢?
创建一个bean A
@Component
public class A {
private B b;
public void setB(B b) {
this.b = b;
}
public A (){
System.out.println("默认构造");
}
public A(B a){
System.out.println("构造参数b");
}
public A(B b,C c){
System.out.println("构造参数 b ,c");
}
public A(B b,C c ,D d){
System.out.println("构造参数 b ,c,d");
}
}
我定义了四个构造方法,目的就是想知道Spring如何推断构造方法的。 下面直接通过源码,一探究竟
找到spring创建bean的方法 doGetBean方法,断点打到getSingle方法上然后条件是beanName == a,第一次执行这里getSingle可定返回空。然后找到createBean 方法,createBea方法调用doCreateBean,doCreateBean调用createBeanInstance,createBeanInstance调用 determineConstructorsFromBeanPostProcessors方法;
进入determineConstructorsFromBeanPostProcessors中,发现这里调用了bean的后置处理器BeanPostProcessor,其中推断构造方法,只有AutoWiredAnnotationBeanPostProcess这个处理器干了事情。
进去这个处理器中的determineCandidateConstructors方法,下面的逻辑就是推断构造方法的整个逻辑。下面进行详细分析,放出全局代码吧。
if (candidateConstructors == null) {
// Fully synchronized resolution now...
synchronized (this.candidateConstructorsCache) {
candidateConstructors = this.candidateConstructorsCache.get(beanClass);
if (candidateConstructors == null) {
Constructor<?>[] rawCandidates;
try {
rawCandidates = beanClass.getDeclaredConstructors();
} catch (Throwable ex) {
throw new BeanCreationException("");
}
List<Constructor<?>> candidates = new ArrayList<>(rawCandidates.length);
Constructor<?> requiredConstructor = null;
Constructor<?> defaultConstructor = null;
Constructor<?> primaryConstructor = BeanUtils.findPrimaryConstructor(beanClass);
int nonSyntheticConstructors = 0;
for (Constructor<?> candidate : rawCandidates) {
if (!candidate.isSynthetic()) {
nonSyntheticConstructors++;
} else if (primaryConstructor != null) {
continue;
}
AnnotationAttributes ann = findAutowiredAnnotation(candidate);
if (ann == null) {
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) {
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) {
if (!candidates.isEmpty()) {
throw new BeanCreationException(beanName,
"Invalid autowire-marked constructors: " + candidates +
". Found constructor with 'required' Autowired annotation: " +
candidate);
}
requiredConstructor = candidate;
}
candidates.add(candidate);
} else if (candidate.getParameterCount() == 0) {
defaultConstructor = candidate;
}
}
if (!candidates.isEmpty()) {
// Add default constructor to list of optional constructors, as fallback.
if (requiredConstructor == null) {
if (defaultConstructor != null) {
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));
}
}
candidateConstructors = candidates.toArray(new Constructor<?>[0]);
} else if (rawCandidates.length == 1 && rawCandidates[0].getParameterCount() > 0) {
candidateConstructors = new Constructor<?>[]{rawCandidates[0]};
} 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);
}
}
}
1.
Constructor<?>[] candidateConstructors = this.candidateConstructorsCache.get(beanClass)
从candidateConstructorsCache 这个map中尝试获取key为beanClass的Constructor[]数组,如果为空,进行同步在获取一遍,同步主要考虑到了多线程情况
2.
rawCandidates = beanClass.getDeclaredConstructors()
得到A的声明的所有构造方法,4个
3.
List<Constructor<?>> candidates = new ArrayList<>(rawCandidates.length);
定义要选举的构造方法集合,长度为bean构造方法的个数
4.
Constructor<?> requiredConstructor = null;
这个是记录有@AutoWire()并且是require=true的构造方法,后面根据源码证明
Constructor<?> defaultConstructor = null;记录默认的构造方法
Constructor<?> primaryConstructor = BeanUtils.findPrimaryConstructor(beanClass);
这个是记录Kotlin处理的类,具体啥是Kotlin。。。。。不知道~,一般情况下这个记录都是空的,Spring做的还是很全面的。
int nonSyntheticConstructors = 0;
记录不是合成构造函数的个数,一般情况下都不是合成的。
5.
遍历A声明的构造函数
AnnotationAttributes ann = findAutowiredAnnotation(candidate);
判断构造函数是不是被@Autowire或@Value注解
6.
因为我们的构造方法没有一个被@Autowire注解,所以为空。
有的话,就会判断@Autowire的require的属性是不是为true,如果为true,把这个contructor赋值给之前定义的变量requiredConstructor。然后把这个constructor放到candidates集合中。
此时同一类只能有一个构造函数被require=true修饰,如果有多个@Autowire,不管require的值是不是true,Spring 会直接抛异常。但可以有多个@Autowire(required=false)修饰的构造方法
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) {
if (!candidates.isEmpty()) {
throw new BeanCreationException(beanName,
"Invalid autowire-marked constructors: " + candidates +
". Found constructor with 'required' Autowired annotation: " +
candidate);
}
requiredConstructor = candidate;
}
candidates.add(candidate);
7.
空的话,会进行判断构造函数的参数长度是不是为0
else if (candidate.getParameterCount() == 0) { defaultConstructor = candidate; }
如果条件满足的话,就把它赋值给变量defaultConstructor
8.
此时遍历流程已经还原完了,下面对遍历结果进行处理
首先判断 candidates集合是不是为空,从上面的遍历流程来看,只有在用@Autowire修饰的情况下,才放到candidates集合中。
8.1
如果candidates不为空,在判断requiredConstructor为空和defaultConstructor不为空把defaultConstructor放到candidates集合中。否则不把defaultConstructor放到candidates集合中。在把candidates拷贝到candidateConstructors数组中。
if (!candidates.isEmpty()) { // Add default constructor to list of optional constructors, as fallback. if (requiredConstructor == null) { if (defaultConstructor != null) { 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)); } } candidateConstructors = candidates.toArray(new Constructor<?>[0]); }
8.2
如果candidates为空,再判断rawCandidates是不是只有一个构造方法,并且构造数的参数大于0,
else if (rawCandidates.length == 1 && rawCandidates[0].getParameterCount() > 0) { candidateConstructors = new Constructor<?>[]{rawCandidates[0]}; }
8.3
再把推断的构造方法数组放到缓存map中。为了方便下次推断。
this.candidateConstructorsCache.put(beanClass, candidateConstructors);
9.
9.1
如果没有推断到构造方法,并且A不是自动注入模式的话(by AUTOWIRE_CONSTRUCTOR),会跳过这个方法。
9.2
如果有推断到构造方法或者bean的注入类型为自动注入的话,则执行。
因为我们的A不是自动注入模式的,并且推断的构造方法为空,会跳过下面的方法,下面的逻辑有点复杂,后面再说。
10.
由于构造方法没有推断到,会执行instantiateBean方法,constructorToUse = clazz.getDeclaredConstructor();这一行代码会把A类中默认无参的构造方法赋给constructorToUse
bd.resolvedConstructorOrFactoryMethod = constructorToUse;
再把它放到bd中的resolvedConstructorOrFactoryMethod属性上,方面下次获取。
最后执行实例化
return (KotlinDetector.isKotlinReflectPresent() && KotlinDetector.isKotlinType(ctor.getDeclaringClass()) ? KotlinDelegate.instantiateClass(ctor, args) : ctor.newInstance(args));
总结:
1.spring首先拿到所有声明的构造方法,在判断有没有被@Autowire注解的,
1.1.有,在判断requiredConstructor是不是为空,下面的判断执行完最后会放到candidates集合中
1.1.1.requiredConstructor不为空,直接抛异常。
1.1.2.requiredConstructor为空,在判断required
1.1.2.1.required=true,在判断candidates是不是为空,
1.1.2.2 candidates为空,requiredConstructor赋值
1.1.2.3.candidates不为空,直接抛异常。(构造函数不能被多个@Autowire(required=true)修饰)
1.2.没有,在判断是不是无参,如果是,defaultConstructor赋值
2.判断 candidates集合
2.1.不为空,在判断requiredConstructor
2.1.1 requiredConstructor为空,并且defaultConstructor不为空时,把默认的构造函数放到candidates集合中
2.2.为空,在判断构造函数是不是只有一个并且带有参数
推断完成后,又会根据推断的构造函数和bean装配类型要不要进行二次推断,确保能够找到唯一一个构造方法并能成功实例化。。。。二次推断后面再细说吧。