Spring源码分析の构造方法推断
文章目录
- 前言
- 一、createBeanInstance
- 1.1、determineConstructorsFromBeanPostProcessors
- 1.2、instantiateBean
- 1.3、autowireConstructor
前言
在Spring中,如果某个bean只有一个无参的构造方法,那么就会根据该构造方法进行实例化:
但是如果存在多个呢?
以及手动使用
@AutoWired
注解,乃至更复杂的情况?
这里就涉及到Spring对于构造方法的推断。构造方法的推断,是属于bean生命周期中的
实例化阶段
:
一、createBeanInstance
createBeanInstance
是对于bean进行实例化
的方法:
- 参数一:将要实例化的bean的名称。
- 参数二:将要实例化的bean的定义。
- 参数三:getBean方法传入的参数。
其中args
参数,可以理解为指定Spring使用何种构造方法:
这样写默认使用的会是无参构造,为什么等会会说明
而在getBean
方法中指定了这个参数,Spring会按照指定的参数去选择构造方法。
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);
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());
}
Supplier<?> instanceSupplier = mbd.getInstanceSupplier();
//可以在bean定义中指定需要创建哪一个bean
//例: beanDefinition.setInstanceSupplier(()->new OrderService());
//创建出的就是OrderService的实例
if (instanceSupplier != null) {
return obtainFromSupplier(instanceSupplier, beanName);
}
//如果bean定义中包含工厂方法名称,则通过工厂方法来实例化bean
if (mbd.getFactoryMethodName() != null) {
return instantiateUsingFactoryMethod(beanName, mbd, args);
}
//-----------------和构造方法有关的逻辑--------------------
//resolved用于标记构造函数是否已解析
//autowireNecessary标记是否需要自动装配构造函数。
boolean resolved = false;
boolean autowireNecessary = false;
// // 如果args为null,则检查构造函数是否已经解析并缓存
if (args == null) {
synchronized (mbd.constructorArgumentLock) {
//这个属性保存了bean定义中解析出来的构造函数或工厂方法。
//如果这个属性不为null,说明bean的构造函数(或者工厂方法)已经被解析并准备好。
if (mbd.resolvedConstructorOrFactoryMethod != null) {
//标记resolved为true,表示构造函数已经解析
resolved = true;
//确定是否需要自动装配。
autowireNecessary = mbd.constructorArgumentsResolved;
}
}
}
//如果构造函数已解析,则根据是否需要自动装配来决定创建bean的方式。
if (resolved) {
//如果需要自动装配
if (autowireNecessary) {
//1.3、autowireConstructor 进行构造函数自动装配
return autowireConstructor(beanName, mbd, null, null);
}
else {
//1.2、instantiateBean 直接使用已解析的构造函数实例化bean。
return instantiateBean(beanName, mbd);
}
}
//1.1、determineConstructorsFromBeanPostProcessors 构造方法的推论
Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);
//推断出的构造不为空 或者 bean定义设置成了允许Spring去自己推断构造 或者 bean定义中有构造参数或传入了构造参数
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);
}
//如果没有任何候选构造函数或首选构造函数,则使用默认的无参构造函数实例化bean。
return instantiateBean(beanName, mbd);
}
在上面这段代码中,首先会去检查缓存,resolved
表示构造函数是否已解析,而autowireNecessary
表示是否需要自动装配构造函数。那么什么情况下autowireNecessary
会被设置成true?
@Component
public class MyBean {
private final OtherBean otherBean;
@Autowired
public MyBean(OtherBean otherBean) {
this.otherBean = otherBean;
}
}
mbd.resolvedConstructorOrFactoryMethod != null
表示的是重复创建同一个bean
的情况,Spring可以重用已解析的构造函数,避免每次都解析构造函数。
1.1、determineConstructorsFromBeanPostProcessors
determineConstructorsFromBeanPostProcessors
用于构造方法的推论。能走到该方法,说明:
- 构造函数之前没有被解析,也就是该bean第一次被创建。
- 和传入的
args
无关,无论是否传递该参数,只要条件1满足,都会进行推断。
AbstractAutoProxyCreator是一个空实现,真正的实现是AutoWired…
@Override
@Nullable
public Constructor<?>[] determineCandidateConstructors(Class<?> beanClass, final String beanName)
throws BeanCreationException {
// 1. 检查是否存在查找方法(@Lookup注解的方法),如果是第一次检查该bean的查找方法,则处理查找方法。
if (!this.lookupMethodsChecked.contains(beanName)) {
// 如果beanClass是一个候选类
if (AnnotationUtils.isCandidateClass(beanClass, Lookup.class)) {
try {
// 从当前beanClass开始遍历所有继承的类
Class<?> targetClass = beanClass;
do {
// 遍历当前类的所有方法
ReflectionUtils.doWithLocalMethods(targetClass, method -> {
// 如果方法上有@Lookup注解
Lookup lookup = method.getAnnotation(Lookup.class);
if (lookup != null) {
Assert.state(this.beanFactory != null, "No BeanFactory available");
// 创建一个LookupOverride对象,用于后续处理
LookupOverride override = new LookupOverride(method, lookup.value());
try {
// 获取bean的定义
RootBeanDefinition mbd = (RootBeanDefinition)
this.beanFactory.getMergedBeanDefinition(beanName);
// 添加Override到bean的methodOverrides中
mbd.getMethodOverrides().addOverride(override);
}
catch (NoSuchBeanDefinitionException ex) {
throw new BeanCreationException(beanName,
"Cannot apply @Lookup to beans without corresponding bean definition");
}
}
});
// 向上遍历父类
targetClass = targetClass.getSuperclass();
}
while (targetClass != null && targetClass != Object.class);
}
catch (IllegalStateException ex) {
throw new BeanCreationException(beanName, "Lookup method resolution failed", ex);
}
}
// 将该bean名称标记为已检查过
this.lookupMethodsChecked.add(beanName);
}
// 2. 尝试从缓存中获取该beanClass的构造函数
Constructor<?>[] candidateConstructors = this.candidateConstructorsCache.get(beanClass);
if (candidateConstructors == null) {
// 3. 如果缓存中没有,进入同步代码块解析构造函数
synchronized (this.candidateConstructorsCache) {
candidateConstructors = this.candidateConstructorsCache.get(beanClass);
if (candidateConstructors == null) {
Constructor<?>[] rawCandidates;
try {
// 获取bean类的所有构造函数(包括有参和无参的)
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有关,可以忽略
Constructor<?> primaryConstructor = BeanUtils.findPrimaryConstructor(beanClass);
int nonSyntheticConstructors = 0;
// 遍历所有的构造函数
for (Constructor<?> candidate : rawCandidates) {
if (!candidate.isSynthetic()) {
//一般情况下的构造函数,nonSyntheticConstructors计数+1
nonSyntheticConstructors++;
}
else if (primaryConstructor != null) {
continue; //和Kotlin有关,可以忽略
}
// 查找构造函数上是否存在@Autowired注解
MergedAnnotation<?> 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) {
}
}
}
//如果构造函数上存在@Autowired注解
if (ann != null) {
// 如果已找到required标记的构造函数,则抛出异常
if (requiredConstructor != null) {
//因为一个bean只能有一个required构造函数
throw new BeanCreationException(beanName,
"Invalid autowire-marked constructor: " + candidate +
". Found constructor with 'required' Autowired annotation already: " +
requiredConstructor);
}
// 判断@Autowired是否标记为required
boolean required = determineRequiredStatus(ann);
if (required) {
if (!candidates.isEmpty()) { // 如果已经有候选构造函数
// 抛出异常,因为一个bean不能同时有多个required构造函数
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
defaultConstructor = candidate;
}
}
// 如果找到autowire标记的构造函数,处理requiredConstructor
if (!candidates.isEmpty()) {
// 如果没有找到required为ture构造函数
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]};
}
//和Kotlin有关,可以忽略
else if (nonSyntheticConstructors == 2 && primaryConstructor != null &&
defaultConstructor != null && !primaryConstructor.equals(defaultConstructor)) {
candidateConstructors = new Constructor<?>[] {primaryConstructor, defaultConstructor};
}
//和Kotlin有关,可以忽略
else if (nonSyntheticConstructors == 1 && primaryConstructor != null) {
candidateConstructors = new Constructor<?>[] {primaryConstructor};
}
// 如果没有候选构造函数
else {
candidateConstructors = new Constructor<?>[0];
}
// 将解析结果缓存起来
this.candidateConstructorsCache.put(beanClass, candidateConstructors);
}
}
}
// 返回找到的候选构造函数,如果没有找到,则返回null 走默认无参构造的逻辑
return (candidateConstructors.length > 0 ? candidateConstructors : null);
}
这一块的逻辑非常复杂,这里仅仅用两种常见的情况进行说明:
一个默认的无参构造,一个有参构造
首先得到OrderService
的所有构造方法:
遍历所有的构造方法:
找注入点,现在
OrderService
上没有任何加了@AutoWired
的构造方法。
Class<?> userClass = ClassUtils.getUserClass(beanClass);
的逻辑:
如果当前bean是被cglib代理过的,就去父类中找。
下一个if也不满足,因为当前构造方法上没有
@AutoWired
第一个遍历到的是无参构造方法,参数的个数为0,所以被标记为默认的构造:
第二个遍历到的是有参构造方法,流程和第一个类似,在执行完这个循环后,
defaultConstructor
被设置成了无参构造,而nonSyntheticConstructors
集合的个数为2:
下面的条件都不满足,会进入最后的else:
最终返回null,返回null代表什么,会在instantiateBean里说明:
再简单地看下加上了@AutoWired
的情况:
第一次循环的是无参构造
,最终会加入defaultConstructor
第二次循环的是带有
@AutoWired
注解的有参构造,找到了注入点:
@AutoWired
注解的required参数默认为true,这里进行了判断,如果有多个加上了@AutoWired
注解,并且没有显式指定required属性,或者required都为true的情况下,会报错。
然后将当前的构造方法设置成需要的构造方法:
在放入缓存后,返回的不是null,而是加上了
@AutoWired
注解的构造:
设置了多个
@AutoWired
注解的构造,会出现异常
简单地小结一下
determineConstructorsFromBeanPostProcessors
方法:如果当前没有加
@AutoWired
注解:
- 多个有参构造,并且有一个无参构造,返回null
- 有多个有参构造,没有默认的无参构造,报错
- 只有一个无参构造,返回null
- 只有一个有参构造,返回该有参构造
如果当前加
@AutoWired
注解:
- 有多个require为true的,报错
- 只有一个require为true的,返回该构造
- 没有require为true的,返回所有构造,包括无参
1.2、instantiateBean
instantiateBean
的底层最终是采用默认的无参构造去创建对象:
1.3、autowireConstructor
autowireConstructor
是处理determineConstructorsFromBeanPostProcessors
方法的返回不为null的逻辑,包括当前没有加@AutoWired
注解,只有一个有参构造的情况,以及如果当前加@AutoWired
注解,只有一个require为true的、没有require为true的情况。
- 参数一:当前bean的名称。
- 参数二:当前bean的定义。
- 参数三:推断出的构造方法。
- 参数四:显式的构造函数参数。
这段代码最复杂的地方在于歧义处理,即:如果存在构造函数的类型匹配度相同的多个候选项,则会处理歧义情况,有机会单独开一篇说明。