spring -- 循环依赖之SingletonObjects ,earlySingletonObjects和singletonfactories一级,二级和三级缓存 和 singletonsCurrentlyInCreation
前提:允许bean提前暴露(属性还没有赋值,有空的类对象) ,允许循环依赖 (循环依赖才往三级缓存中添加数据)
循环依赖的情况 一 (属性中循环依赖)
例子:
循环依赖
@Component public class CircleRefA { @Autowired private CircleRefB circleRefB; }
@Component public class CircleRefB { @Autowired private CircleRefA circleRefA; @Autowired private CircleRefC circleRefC; }
@Component public class CircleRefC { @Autowired private CircleRefA circleRefA; }
假设spring中处理顺序为 CircleRefA (beanName为circleRefA ) -》 CircleRefB (beanName为circleRefB ) -》 CircleRefC (beanName为circleRefC)
先处理CircleRefA
先 getbean(circleRefA),这时一级缓存singletonObjects中没有对应的类,且 singletonCurrentInCreation 中没有 circleRefA , getbean(beanName) 返回 null ,调用getBean(circleRefA , ObjectFactory) 。此时先往 singletonCureentInCreation 中加入 circleRefA(表示正在创建 circleRefA 对应的实例) 。先创建一个属性值为空的A ,称为 早期的bean实例,调用addSingletonFactory ,往在三级缓存中添加circleRefA 对应的 ObjectFactory(此对象,就理解为时 A实例的包装)再进行populateBean进行IOC填充circleRefA 。发现A中有CircleRefB的引用,进行CircleRefB实例化,进行 先 getbean(circleRefB)
在进行getbean(circleRefB),前面的操作一样,后面再进行opulateBean进行IOC填充circleRefB 时,发现B中有CircleRefA的引用,进行getBean(circleRefA) (需要说明的时,属性的编写是认为的,此处可能先进行getBean(circleRefC),分析一样)进行getBean(circleRefA)时,一级缓存singletonObjects中没有对应的类,singetonCureentInCreation中有 circleRefA ;则查找二级缓存earlySingletonObjects ,没有数据;再查找三级缓存,有数据 ,将数据填充到二级缓存earlyObjects , 删除三级缓存,返回给B实例进行填充。发现有C类属性,进行 getbean(circleRefC)
在进行getbean(circleRefC),前面操作同getBean(circleRefA)。后面再进行opulateBean进行IOC填充circleRefC 时,发现C中有CircleRefA的引用,进行getBean(circleRefA) 。此时getBean(circleRefA) ,是从二级缓存中拿到的数据 ,返回A对应的类。
完成 C 的实例化,一级缓存singletonObjects中添加C的实例,删除 singletosCurrentlyInCreation中的circleRefC ,删除三级级缓存中 circleRefC,删除二级缓存 circleRefC。再递归完成 B , A的实例化(同C的实例化)。
说明:
singletonCureentInCreation 中存bean的名称,表示实例正在创建
这里为什么有一个三级缓存singletonfactories,就是放置早期的bean实例。
为什么有一个二级缓存earlySingletonObjects,其实也是放置早期的bean实例。多次拿 早期的bean实例 这一直接冲这里面拿。
直接放在三级缓存singletonfactories 中 ,不放在earlySingletonObjects中,功能上不是也可以吗?是的
但是,其实获取三级缓存的方式是
源码 :
//添加 三级缓存
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
protected void addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory) { Assert.notNull(singletonFactory, "Singleton factory must not be null"); synchronized (this.singletonObjects) { // 如果 一级缓存 中不存在 if (!this.singletonObjects.containsKey(beanName)) { // 设置 三级缓存 ,缓存 的 是 singletonFactory 对象 this.singletonFactories.put(beanName, singletonFactory); // 删除 二级缓存 this.earlySingletonObjects.remove(beanName); this.registeredSingletons.add(beanName); } } }
获取三级缓存
ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
singletonObject = singletonFactory.getObject();
其中
@FunctionalInterface public interface ObjectFactory<T> { /** * Return an instance (possibly shared or independent) * of the object managed by this factory. * @return the resulting instance * @throws BeansException in case of creation errors */ T getObject() throws BeansException; }
三级缓存是一个包装bean的实例的对象,singletonFactory.getObject() 是 ,其实是调用的 getEarlyBeanReference(beanName, mbd, bean) ,
protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) { Object exposedObject = bean; if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) { for (BeanPostProcessor bp : getBeanPostProcessors()) { if (bp instanceof SmartInstantiationAwareBeanPostProcessor) { SmartInstantiationAwareBeanPostProcessor ibp = (SmartInstantiationAwareBeanPostProcessor) bp; exposedObject = ibp.getEarlyBeanReference(exposedObject, beanName); } } } return exposedObject; }
这个地方就是预留了一个点位,进行操作 早期的类对象 ,将经过处理(有处理过程,可以放回原始的bean早期类对象,也可能不是,实现BeanPostProcessor接口,重写getEarlyBeanReference就行,完全可以自定义修改) 。
就是我们说的三级缓存中,其实可以对 早期的类对象 进行自定已处理 。将处理完的对象 ,放在二级缓存中,若还有循环依赖的 处理 ,拿的是 经过处理的 早期的类对象
循环依赖的情况 二 (多例循环依赖scope 为 prototype )
往三级缓存中添加数据源码
boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences && isSingletonCurrentlyInCreation(beanName)); if (earlySingletonExposure) { if (logger.isDebugEnabled()) { logger.debug("Eagerly caching bean '" + beanName + "' to allow for resolving potential circular references"); } addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean)); }
都不是单例,不会往三级缓存singletonfactories中添加数据。每次创建的都是新对象,没必要缓存
此时根据 prototypesCurrentlyInCreation 判断是不是再创建的 ,循环依赖的二次报错。
创建是,会现在查
if (isPrototypeCurrentlyInCreation(beanName)) { throw new BeanCurrentlyInCreationException(beanName); }
再防止 this.prototypesCurrentlyInCreation.set(beanName);
循环依赖的情况 三 (构造函数的循环依赖)
@Component public class CircleRefAA { @Autowired public CircleRefAA(CircleRefBB circleRefBB){ System.out.println("---------CircleRefAA----------"); } }
@Component public class CircleRefBB { @Lazy @Autowired public CircleRefBB(CircleRefAA circleRefAA){ System.out.println("---------CircleRefBB----------"); } }
这个时候正在创建 早期的bean实例,三级缓存中没有存数据 ,重复向 singletonsCurrentlyInCreation 中加数据,报错。
if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.add(beanName)) { throw new BeanCurrentlyInCreationException(beanName); }
循环依赖的情况 四 (构造函数的循环依赖加@Lazy)
网上说构造函数的循环依赖加@Lazy可以解决
--未完待续
说的比较大白话,中间的一些话语 也不是专业术语,能力有限,单大体上就是
posted on 2021-02-28 21:24 xingshouzhan 阅读(4434) 评论(0) 编辑 收藏 举报