上一篇文章我们介绍了Bean的实例化过程以及相互依赖注入的情况,本篇我们介绍一下循环依赖注入报错。
首先我们要改一下StudentA和StudentB的代码,具体如下:
可以看到在两个类中构造方法都注入了彼此,接着我们断点看一下代码的执行流程。
首先执行到StudentA的doCreateBean
此时缓存中没有StudentA实例,直接走到getSingleton方法
然后走到方法中的beforeSingletonCreation方法
将beanName保存在singletonsCurrentlyInCreation中,标识此beanName对应的对象正在实例化中。
接着调用createBean方法调到doCreateBean中
然后进入createBeanInstance方法中初始化StudentA实例
protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) {
// Make sure bean class is actually resolved at this point.
// 获取class对象
Class<?> beanClass = resolveBeanClass(mbd, beanName);
... ...
// Candidate constructors for autowiring?
// 1.判断是否有@AutoWrite的构造方法
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);
}
由于我们StudentA中有@Autowired注解的构造方法,所以会通过注释第1点处的判断,进入到autowireConstructor方法中
public BeanWrapper autowireConstructor(String beanName, RootBeanDefinition mbd,
@Nullable Constructor<?>[] chosenCtors, @Nullable Object[] explicitArgs) {
... ...
// 对所有构造方法进行排序
AutowireUtils.sortConstructors(candidates);
int minTypeDiffWeight = Integer.MAX_VALUE;
Set<Constructor<?>> ambiguousConstructors = null;
LinkedList<UnsatisfiedDependencyException> causes = null;
for (Constructor<?> candidate : candidates) {
// 获取构造方法参数类型
Class<?>[] paramTypes = candidate.getParameterTypes();
if (constructorToUse != null && argsToUse != null && argsToUse.length > paramTypes.length) {
// 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 {
String[] paramNames = ConstructorPropertiesChecker.evaluate(candidate, paramTypes.length);
if (paramNames == null) {
ParameterNameDiscoverer pnd = this.beanFactory.getParameterNameDiscoverer();
if (pnd != null) {
// 获取构造方法参数名称
paramNames = pnd.getParameterNames(candidate);
}
}
// 1.获取构造方法中的参数实例对象
argsHolder = createArgumentArray(beanName, mbd, resolvedValues, bw, paramTypes, paramNames,
getUserDeclaredConstructor(candidate), autowiring, candidates.length == 1);
}
... ...
}
... ...
}
Assert.state(argsToUse != null, "Unresolved constructor arguments");
bw.setBeanInstance(instantiate(beanName, mbd, constructorToUse, argsToUse));
return bw;
}
此时会在createArgumentArray方法这里准备好调用构造方法时用到的所有参数值,StudentA的构造方法中的studentB对象就是在这里进行实例化,我们接着往下看
private ArgumentsHolder createArgumentArray(
String beanName, RootBeanDefinition mbd, @Nullable ConstructorArgumentValues resolvedValues,
BeanWrapper bw, Class<?>[] paramTypes, @Nullable String[] paramNames, Executable executable,
boolean autowiring, boolean fallback) throws UnsatisfiedDependencyException {
... ...
try {
// 获取@AutoWired注解的构造方法中的参数实例
Object autowiredArgument = resolveAutowiredArgument(
methodParam, beanName, autowiredBeanNames, converter, fallback);
args.rawArguments[paramIndex] = autowiredArgument;
args.arguments[paramIndex] = autowiredArgument;
args.preparedArguments[paramIndex] = new AutowiredArgumentMarker();
args.resolveNecessary = true;
}
catch (BeansException ex) {
throw new UnsatisfiedDependencyException(
mbd.getResourceDescription(), beanName, new InjectionPoint(methodParam), ex);
}
... ...
return args;
}
最后走到我们之前分析BeanFactory实例化@Autowired注解的类属性一样的流程。
最后走到BeanFactory的getBean方法,开始进行StudentB的实例化流程。
所以接下来就会走到StudentB的doGetBean方法
此时缓存中没有StudentB实例,跟StudentA一样,继续往下走到getSingleton方法
同样的,在getSingleton里的beforeSingletonCreation方法中标识studentB处于正在实例化中。
此时可以看到singletonsCurrentlyInCreation中有存在两个正在实例化中的对象
接着继续调用到了createBean方法
来到了doCreateBean方法
然后接下来的流程就跟StudentA的一样,此时StudentB也会走到使用@AutoWrite的构造方法创建实例这里
此时获取到StudentB构造方法中的StudentA参数,开始对StudentA进行实例化
最后走到BeanFactory的getBean方法
所以接下来BeanFactory会调用doGetBean方法再一次开始StudentA的实例化,从这里我们可以发现,前面的流程中的StudentA和StudentB目前扔处于获取构造方法参数值的阶段中,还没有达到调用构造方法创建实例的条件。
我们接着继续看一下doGetBean方法
此时缓存中也没有StudentA实例,所以继续往下走
此时进入到beforeSingletonCreation方法中
由于singletonsCurrentlyInCreation集合已经存在studentA,所以this.singletonsCurrentlyInCreation.add(beanName)将会返回false,此时就进入if方法体中,抛出了循环依赖的异常。