Spring循环依赖

定义、举例

循环依赖是指Bean对象循环引用,两个或多个bean之间相互持有对方的引用,导致Spring容器无法初始化它们。

例如,A引用了B,发现B还没创建,于是开始创建B,在创建B的过程中发现B又引用了A,但A还没创建好。

出现循环依赖的场景

  • Bean对象实例化阶段(因为在实例化时需要解析依赖关系)
  • JVM使用引用计数器进行垃圾回收时,可能会出现循环依赖导致内存泄漏
  • 线程互相占用对方的锁,发生死锁

通过三级缓存解决循环依赖

  • 一级缓存(Singleton Objects)​:单例池、存放完全初始化后的 Bean。
  • 二级缓存(Early Singleton Objects)​:缓存实例化但未初始化的 Bean(半成品)。
  • 三级缓存(Singleton Factories)​:缓存的是ObjectFactory,表示对象工厂,用于生成普通对象或者代理对象,暴露 Bean到二级缓存。

只用两级缓存可以吗?

如果只用一级缓存和二级缓存,Spring 可以处理 ​普通的循环依赖​(例如两个 Bean 互相依赖),但无法处理 ​涉及代理对象(AOP 动态代理)的循环依赖

构造方法出现了循环依赖怎么解决?

注入方式是构造函数的情况下:

原因:由于 bean 的生命周期中构造函数是第一个执行的, spring 框架并不能解决构造函数的的
依赖注入
解决方案:使用 @Lazy 进行懒加载,什么时候需要对象再进行 bean 对象的创建。

示例:

@Component
public class BeanA {
    private final BeanB beanB;

    @Autowired
    public BeanA(@Lazy BeanB beanB) { // 使用 @Lazy 延迟加载 BeanB
        this.beanB = beanB;
    }
}

@Component
public class BeanB {
    private final BeanA beanA;

    @Autowired
    public BeanB(@Lazy BeanA beanA) { // 使用 @Lazy 延迟加载 BeanA
        this.beanA = beanA;
    }
}
  • 当Spring创建BeanA时,发现它依赖BeanB,但由于@Lazy的存在,Spring不会立即初始化BeanB,而是注入一个代理对象。
  • 当BeanA真正使用到BeanB时,代理对象会出发BeanB的初始化。
  • 同时,BeanB依赖BeanA也会延迟加载。

@Lazy的优缺点:

优点:
  • 解决构造函数注入的循环依赖问题。
  • 延迟加载可以减少启动时的初始化开销。
缺点:
  • 增加了代理对象的复杂性,可能影响调试。
  • 如果滥用 @Lazy,可能导致程序行为难以预测。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值