spring三级缓存处理循环依赖

带着问题看源码:为什么要三级缓存,两级行不行?

spring初始化过程的分析这里不再赘述,可参考另外一篇https://www.cnblogs.com/reboot30/p/8505664.html

我们这里从org.springframework.beans.factory.support.AbstractBeanFactory#doGetBean直接开始,如果从三级缓存能够获取到bean的话,就直接返回bean,

在getSingleton中将bean从三级缓存升级到二级缓存,这点在后面非常有用, 创建bean的时候会根据二级缓存中有没有bean实例判断是否该bean在创建过程中被

别人引用了。

如果从一、二、三级缓存均未获取到bean,进入创建bean过程:

图1-1:

public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
        Assert.notNull(beanName, "Bean name must not be null");
        synchronized (this.singletonObjects) {
       // 检查一级缓存是否存在该bean Object singletonObject
= this.singletonObjects.get(beanName); if (singletonObject == null) { if (this.singletonsCurrentlyInDestruction) { throw new BeanCreationNotAllowedException(beanName, "Singleton bean creation not allowed while singletons of this factory are in destruction " + "(Do not request a bean from a BeanFactory in a destroy method implementation!)"); } if (logger.isDebugEnabled()) { logger.debug("Creating shared instance of singleton bean '" + beanName + "'"); }
          // 将bean放入singletonsCurrentlyInCreation beforeSingletonCreation(beanName);
boolean newSingleton = false; boolean recordSuppressedExceptions = (this.suppressedExceptions == null); if (recordSuppressedExceptions) { this.suppressedExceptions = new LinkedHashSet<>(); } try {
            // 调用入参singletonFactory创建bean singletonObject
= singletonFactory.getObject(); newSingleton = true; } catch (IllegalStateException ex) { // Has the singleton object implicitly appeared in the meantime -> // if yes, proceed with it since the exception indicates that state. singletonObject = this.singletonObjects.get(beanName); if (singletonObject == null) { throw ex; } } catch (BeanCreationException ex) { if (recordSuppressedExceptions) { for (Exception suppressedException : this.suppressedExceptions) { ex.addRelatedCause(suppressedException); } } throw ex; } finally { if (recordSuppressedExceptions) { this.suppressedExceptions = null; }
            // 将beanName从singletonsCurrentlyInCreation移除 afterSingletonCreation(beanName); }
if (newSingleton) {
            // 创建成功,将bean升级到一级缓存 addSingleton(beanName, singletonObject); } }
return singletonObject; } }

回到图1-1,第二个入参为函数接口org.springframework.beans.factory.ObjectFactory,实际调用子类如下方法:org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#createBean(java.lang.String, org.springframework.beans.factory.support.RootBeanDefinition, java.lang.Object[])

最终调用doCreateBean创建bean:

 org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#doCreateBean核心代码片段如下图一一列出:

总体步骤为:

1.创建实例

 

2.将刚创建的早期bean放入三级缓存

 

从三级缓存获取bean时,实际是通过org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#getEarlyBeanReference方法返回bean,这里要注意,返回的bean有可能是经过SmartInstantiationAwareBeanPostProcessor处理过的。

3.populateBean、initializeBean

4.如果暴露了早期bean,就从一、二级缓存获取bean,目的是判断是否有被循环依赖。

5.如果步骤4获取到了就比较早期暴露出去的bean和initializeBean之后的bean是否是同一个:

  如果是,说明早期bean A从暴露出去之后没有发生变化,直接返回4中获取的bean,为什么?

因为populateBean的时候如果注入的bean B循环引用了bean A,那么会在一开始的org.springframework.beans.factory.support.AbstractBeanFactory#doGetBean处将bean A从三级缓存上升到二级缓存,由上面分析我们知道,三级缓存存放的是ObjectFactory,getObject实际调用的是org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#getEarlyBeanReference,这个里面有可能改变原始bean,所以,当initializeBean前后还是同一个对象时,以缓存中的bean为主。

  如果不是,说明initializeBean内部改变了早期bean,比如某个beanPostProcessor给bean创建了代理,这个时候就存在问题了,因为早期bean被暴露出去给别的bean使用了,存在一致性问题,这个时候就会抛出BeanCurrentlyInCreationException异常。

 

posted on 2021-04-21 15:06  砌码匠人  阅读(254)  评论(0编辑  收藏  举报

导航