Spring为什么使用三级缓存而不是两级解决循环依赖问题?( 三 )

若初始化阶段的后置处理器对对象做了代理,Spring是如何处理的?在Spring中若在initializeBean阶段的后置处理器对对象做了代理,那么Spring会对做依赖检查,具体代码如下:
 if (earlySingletonExposure) {// 这里我们还拿A、B两个对象举例// 尝试从二级缓存中获取A,第二个参数是false表示不再从三级缓存获取(也就是执行ObjectFactory.getObject())Object earlySingletonReference = getSingleton(beanName, false);if (earlySingletonReference != null) {// exposedObject是执行initializeBean方法返回的A,可能是个proxy_A// bean是首次实例化的A,若这两个对象不相等,说明initializeBean方法返回了代理对象,需要进行依赖检查if (exposedObject == bean) {exposedObject = earlySingletonReference;}// 依赖检查逻辑// 这一大段就是在检查,检查依赖了A对象的Bean集合// 这里很好理解:例如B依赖了A,那么如果B没有创建好,那么我们把B从缓存删掉,在之后的构建中让其重新依赖A_proxy// 若B已经创建好了,那么很不幸,只能报错了,因为B这时候依赖的是一个普通A,而不是proxy_Aelse if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {String[] dependentBeans = getDependentBeans(beanName);Set<String> actualDependentBeans = new LinkedHashSet<String>(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.");}}}}为什么Spring采用三级缓存设计?我们再回到最初的问题上,其实上述整个设计推演过程就已经很好的回答了这个问题,这里再做一下补充 。从上述Spring源码可知,其在第三级缓存中放入的是匿名类ObjectFactory,每次需要获取对象实例就会调用其getObject方法 。我们举个例子:
假如现在没有earlySingletonObjects这一层缓存(也就是第二级缓存),也就是两级缓存结构,现在有三个对象,其依赖关系如下A->B、B->A和C、C->A,从这个依赖关系可以得出,A所在的ObjectFactory会被调用两次getObject(),如果两次都返回不同的proxy_A(毕竟后置处理器的代码是使用者自己写的,可能代码是new Proxy(A)),那么就可能导致,B、C对象依赖的proxy_A不是一个对象,那么这种设计是致命的 。
这个案例也从侧面反映了三层缓存的设计必要性、必然性,也是为了让框架更加的灵活健壮,以上就是我对Spring bean 三层缓存设计的理解,如有疑问欢迎在评论区讨论留言 。




推荐阅读