三级缓存
//一级缓存,存放的是完整的bean
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);
//二级缓存,存放的是半成品的bean,未完成属性注入
private final Map<String, Object> earlySingletonObjects = new HashMap<>(16);
//三级缓存,存放的是bean工厂,用来生成bean。
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);
循环依赖
如何解决循环依赖
通过三级缓存可以很好的解决循环依赖:
1,A创建过程中需要B,于是A将自己放到三级缓里面,去实例化B
2,B实例化的时候发现需要A,于是B先查一级缓存,没有,再查二级缓存,还是没有,再查三级缓存,找到了A然后把三级缓存里面的这个A放到二级缓存里面,并删除三级缓存里面的A
3,B顺利初始化完毕,将自己放到一级缓存里面(此时B里面的A依然是创建中状态)
然后回来接着创建A,此时B已经创建结束,直接从一级缓存里面拿到B,然后完成创建,并将A自己放到一级缓存里面。
为什么构造器注入无法解决循环依赖问题
- 这是因为当一个类在构造函数中需要依赖另一个类的实例时,它必须等待另一个类的实例完成构造才能完成自己的构造。但是,由于另一个类也依赖于当前类的实例,它也需要等待当前类的实例完成构造。这就形成了一个相互等待的死循环,导致无法完成依赖注入。
当一个单例内部属性是多例bean时,也无法解决循环依赖
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
@Service
public class A {
@Autowired
private B b;
}
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
@Service
public class B {
@Autowired
private A a;
}
结果:
不报错。需要注意的是本例中启动时是不会报错的(因为非单例Bean默认不会初始化,而是使用时才会初始化),所以很简单咱们只需要手动getBean()或者在一个单例Bean内@Autowired一下它即可
但是:
// 在单例Bean内注入
@Autowired
private A a;
报错:
当单例 bean 和多例 bean 相互之间存在循环依赖时,容器在创建对象时会遇到两个主要问题:
- 单例 bean 的创建过程中需要引用一个还未创建的多例 bean 实例。由于多例 bean 的创建是延迟到每次请求时才进行的,所以容器无法提供未创建的多例 bean 实例。
- 多例 bean 的创建过程中需要引用一个还未创建的单例 bean 实例。单例 bean 在容器初始化时被创建,但它的依赖可能包含一个还未创建的多例 bean 实例,因此容器也无法提供未创建的多例 bean 实例。