问题描述
有多个对象,A依赖B,B依赖A。导致实例化的时候会进入死循环导致内存溢出。
三种循环依赖
1.构造器的循环依赖(spring解决不了)
构造器中包含其他bean,spring容器会将每个正在创建的bean放在三级缓存中,并且创建过程中一直放在这个三级缓存中,如果在创建bean的过程中,发现自己已经在三级缓存中就抛出BeanCurrentlyInCreatingException。
2.setter方式,单例模式(spring能解决)
@Service
public class A {
@Autowire
private B b;
}
@Service
public class B {
@Autowire
private A a;
}
解决方案
使用了三级缓存。创建Bean分为3个阶段,实例->赋值属性->初始化,递归调用时发现Bean还在创建中即为循环依赖。
/** 一级缓存:用于存放完全初始化好的 bean **/
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<String, Object>(256);
/** 二级缓存:存放原始的 bean 对象(尚未填充属性),用于解决循环依赖 */
private final Map<String, Object> earlySingletonObjects = new HashMap<String, Object>(16);
/** 三级级缓存:存放 bean 工厂对象,用于解决循环依赖 */
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<String, ObjectFactory<?>>(16);
/**
bean 的获取过程:先从一级获取,失败再从二级、三级里面获取
创建中状态:是指对象已经 new 出来了但是所有的属性均为 null 等待被 init
*/
检测循环依赖的过程
- A创建过程中需要B,先将自己放到3级缓存中,去实例化B
- B实例化的时候需要A,会去一级缓存中查看是否有A,如果没有就去二级缓存,发现还是没有就去三级缓存,找到了
- 把3级缓存里的A放到二级缓存,并删除3级缓存里的A
- B初始化完毕,将自己放到一级缓存里
- 然后回来接着创建A,此时B已经创建结束,直接从一级缓存中找到B,然后完成创建,并将自己A放到一级缓存中
- 顺利创建完A
3.setter方式,原型模式
spring解决不了,prototype作用域的bean,spring容器不进行缓存,无法暴露正在创建的bean。
网友评论