// 肯定是允许早期访问的,否则就无法解决循环依赖了 if (earlySingletonExposure) { // 此时会从一级、二级缓存中获取对象引用,而当前的 A 由于注入已经被转移到了二级缓存中(二级缓存放的就是从三级缓存生成的代理对象) Object earlySingletonReference = getSingleton(beanName, false); // 二级缓存存在说明肯定发生了循环依赖,当然也可能是一级缓存的对象,所以后续还要判断是否有其他的 bean 依赖于当前对象 if (earlySingletonReference != null) { // exposedObject 在存在循环依赖的情况下是不能被 initializeBean() 中的回调方法替换的 if (exposedObject == bean) { // 如果两者相等,那么就将缓存中的对象赋给 exposedObject(也就是本例中 A 的代理对象) exposedObject = earlySingletonReference; } // 不相等,说明对象被替换了,那么就需要检测是否有其他对象依赖于当前对象 elseif (!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()) { thrownew 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 " + "'getBeanNamesForType' with the 'allowEagerInit' flag turned off, for example."); } } } }
此时由于 A 没有任何依赖,那么 Spring 可以明正严顺的将 A 构造完毕,然后在注入给 B。那么也就是说在第一次调用 doGetBean 时,就要完成 A 代理对象的创建。A 代理的创建要满足什么要求呢?起码得是 A 对象自己初始化完毕(在循环依赖中,虽然创建的 A 是早期的,但是由于是相同引用,只要引用所指的对象初始化完就行了)。说到这里我想你应该知道在哪个阶段发生了。
if (earlySingletonExposure) { // 一级、二级缓存不存在 Object earlySingletonReference = getSingleton(beanName, false); // 条件返回 false if (earlySingletonReference != null) { if (exposedObject == bean) { exposedObject = earlySingletonReference; } elseif (!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()) { thrownew 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 " + "'getBeanNamesForType' with the 'allowEagerInit' flag turned off, for example."); } } } }