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);

循环依赖

image

如何解决循环依赖

通过三级缓存可以很好的解决循环依赖:
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 相互之间存在循环依赖时,容器在创建对象时会遇到两个主要问题:

  1. 单例 bean 的创建过程中需要引用一个还未创建的多例 bean 实例。由于多例 bean 的创建是延迟到每次请求时才进行的,所以容器无法提供未创建的多例 bean 实例。
  2. 多例 bean 的创建过程中需要引用一个还未创建的单例 bean 实例。单例 bean 在容器初始化时被创建,但它的依赖可能包含一个还未创建的多例 bean 实例,因此容器也无法提供未创建的多例 bean 实例。
posted @   一个苦逼的23届毕业生  阅读(35)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
点击右上角即可分享
微信分享提示