
相信点进来的同学,一定是和我一样爱学习的好同学,哈哈,或许面试中遇到过,或许刷8股文的时候看到过Spring循环依赖相关的面试题,Spring循环依赖为啥要使用三级缓存来解决这个面试题我被问过很多很多次,而且很难讲清楚。我觉得看过Spring源码后还是要记录下来Spring解决循环依赖的设计思路和技术爱好者分享一波。
说明
看这篇文章的同学需要有对Spring ioc和di流程有了解,知道Spring bean创建和bean属性填充。
//一级缓存,存储可以直接使用的beanprivate final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);//二级缓存 存储不完整对象 不能直接用的 循环依赖时,某些依赖的属性没有设置,这个时候bean就是不完整对象private final Map<String, Object> earlySingletonObjects = new HashMap<>(16);//三级缓冲 存储bean工厂 可以延迟调用实例化 使用的时候才调用工厂方法获取对象private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);//从Spring容器获取bean对象方法protected Object getSingleton(String beanName, boolean allowEarlyReference) {//一级缓存Object singletonObject = this.singletonObjects.get(beanName);if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {synchronized (this.singletonObjects) {//二级缓存singletonObject = this.earlySingletonObjects.get(beanName);if (singletonObject == null && allowEarlyReference) {ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);if (singletonFactory != null) {//三级缓存singletonObject = singletonFactory.getObject();this.earlySingletonObjects.put(beanName, singletonObject);this.singletonFactories.remove(beanName);}}}}return singletonObject;}
这里为什么需要3个缓存呢?为啥2个不行?1个也不行?我们下面开始来看到底为什么?
模拟循环依赖场景
A,B类分别有对方的类属性
public class A {private B b;}
public class B {private A a;}
模拟循环依赖相互手动注入
A a = new A();B b = new B();b.setA(a); //B里面注入不完整的A了a.setB(b); //注入依赖的对象,A里面有B了,a注入完成变成完整的a









下次面试再被问到循环依赖的问题,我会怎么来给面试官说明白呢?
1、Spring通过3个缓存map来解决循环依赖的问题,分别是singletonObjects,singletonFactories,earlySingletonObjects
2、singletonObjects这个缓存是存储完整的对象,可以直接使用的。
3、singletonFactories这个缓存是为了延迟初始化,是解决循环依赖的关键,存在循环依赖注入时,可能注入的对象需要被代理,这个工厂类来实例化一个代理类。
4、earlySingletonObjects这个缓存是为了在a注入b,而b又注入a这个阶段,a是一个半成品,需要用来存储a这种半成品bean的状态。
需要等待a将b注入之后,这个缓存就要移除。
5、singletonFactories和earlySingletonObjects都是存储对象的中间状态,依赖它们保证最终注入的对象是完整的,依赖注入完成后会被清除。
原文作者:服务端技术栈;如有侵权,请联系管理员删除。