Spring三级缓存与循环依赖
三级缓存
//一级缓存,存放的是完整的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 实例。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· 【自荐】一款简洁、开源的在线白板工具 Drawnix