上图是单例对象初始化的过程 ,循环依赖发生在 第二步骤
/** Cache of singleton objects: bean name --> bean instance */
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<String, Object>(256);
/** Cache of singleton factories: bean name --> ObjectFactory */
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<String, ObjectFactory<?>>(16);
/** Cache of early singleton objects: bean name --> bean instance */
private final Map<String, Object> earlySingletonObjects = new HashMap<String, Object>(16);
解决方式主要是依赖 spring的三级缓存
singletonObjects ->单例对象的cache
singletonFactories ->单例对象工厂的cache
earlySingletonObjects ->提前暴光的单例对象的Cache
实例分析
A依赖B B又依赖A
当A创建时 走到下图逻辑 则判断 其BeanDefinition是否为单例 是否允许循环依赖 是否在创建中, 然后满足,调用addSingletonFactory方法
在此方法中,将A放入三级缓存singletonFactories中 然后继续向下走 走到populateBean中 为A设置属性,但是在A的属性中又依赖的B,此时就到三个缓存中分别去找B,但是找不到(因为B此时还未创建),那么接下里就要去创建B
在创建B的过程中,经历与A同样的过程,到设置属性时发现其属性中依赖了A,那么就调用getSingleton去查找A,其过程是先从singletonObjects中获取(找不到 因为此时A还在创建中) 然后再去earlySingletonObjects中找(找不到 因为A还未对外暴露未设置属性的实例) 然后再去singletonFactories中找,因为在创建A时已经把其ObjectFactory放入三级缓存中,所以此时调用其getObject()方法 获取为设置属性的A 并将其放入二级缓存earlySingletonObjects中 将其赋值给B中的A,然后B在执行步骤二和三 完成创建
接着A中的B已经创建完成 此时A接着去执行步骤二,三创建完成
因为A是单例模式,所以此处实例化的A和ObjectFactory.getObject()创建的A指向同一地址,所以此时B中的A也补全完整 从此完成循环依赖
构造注入不能解决循环依赖的原因是:如果A的构造其中依赖了B B的构造器中又依赖了A 在getSingleton中三级缓存需要调用getObject()构造器构造提早暴露但未设置属性的bean,此时就会产生无限递归创建
网友评论