populateBean(beanName, mbd, instanceWrapper);
exposedObject = initializeBean(beanName, exposedObject, mbd);
。。。。
if (earlySingletonExposure) {
Object earlySingletonReference = getSingleton(beanName, false);
if (earlySingletonReference != null) {
if (exposedObject == bean) {
exposedObject = earlySingletonReference;
}
else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {
String[] dependentBeans = getDependentBeans(beanName);
Set<String> actualDependentBeans = new LinkedHashSet<>(dependentBeans.length);
for (String dependentBean : dependentBeans) {
if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) {
actualDependentBeans.add(dependentBean);
}
}
if (!actualDependentBeans.isEmpty()) {
throw new BeanCurrentlyInCreationException(beanName,
"Bean with name '" + beanName + "' has been injected into other beans [" +
StringUtils.collectionToCommaDelimitedString(actualDependentBeans) +
"] in its raw version as part of a circular reference, but has eventually been " +
"wrapped. This means that said other beans do not use the final version of the " +
"bean. This is often the result of over-eager type matching - consider using " +
"'getBeanNamesOfType' with the 'allowEagerInit' flag turned off, for example.");
}
}
}
}
bean :原始对象
exposedObject :初始化后的对象,可能为代理对象
earlySingletonReference :实例化但未初始化的对象,可能为代理对象。Object earlySingletonReference = getSingleton(beanName, false),可以从getSingleton源码中看出,当allowEarlyReference为false时,只在一二级缓存获取值,而二级缓存的值是三级缓存赋值的,若一个对象不存在循环引用,则永远不会从三级缓存中取值赋值到二级缓存中,那么earlySingletonReference是null。
要触发BeanCurrentlyInCreationException,说明exposedObject为代理对象,即在initializeBean方法中bean被代理了。而如果该bean是循环引用的对象,例如A对象(A->B->A),因为执行到此处代码时,B对象已经完全初始化了,而B中引用的A则是从三级缓存中获取到的A对象,但A对象在B初始化完后又进行了一次代理,造成B中的A和A初始化后的A不一样,就会触发该异常。spring是通过下方if判断进行检查,
if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) {
actualDependentBeans.add(dependentBean);
}
该if检查可总结为:如果某个对象初始化后进行了一次代理,而该对象初始化之前已被其它完成初始化的对象引用,则会触发该异常。
@Async 的处理就是在初始化后进行了一次代理,如果对应的bean循环依赖,就会触发该异常
@Transactional 对应的bean若循环依赖,因为该bean对应的代理是在从三级缓存中获取时处理的,而在初始化后exposedObject依旧是原始的bean对象,所以exposedObject和bean相等,此时会从二级缓存中取出代理对象赋值给exposedObject,所以最终返回的exposedObject为代理对象,不会出现该异常。