spring如何解决循环依赖

本文详细讲解了循环依赖的概念,常见于Spring中的构造器和setter注入场景,介绍了Spring如何检测循环依赖,并重点阐述了解决setter注入循环依赖的方法。同时,强调了编码时避免循环依赖的重要性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


一、什么是循环依赖?

循环依赖指的是2个或以上的bean互相持有对方,最终形成闭环。注意区分循环调用(死循环,除非有终止条件)。

二、循环依赖的场景

1.构造器的循环依赖

代码如下(示例):

	@Component
    public class A {
        private B b;

        public A(B b) {
            this.b = b;
        }

    }
	@Component
    public class B {
        private C c;

        public B(C c) {
            this.c = c;
        }
    }
	@Component
    public class C {
        private A a;

        public C(A a) {
            this.a = a;
        }
    }
    

2.setter循环依赖

代码如下(示例):

    @Component
    public class A {
        private B b;
        public void setB(B b) {
            this.b = b;
        }
    }
	@Component
    public class B {
        private C c;
        public void setC(C c) {
            this.c = c;
        }
    }
	@Component
    public class C {
        private A a;
        public void setA(A a) {
            this.a = a;
        }
    }

二、spring如何检测有循环依赖

spring在创建对象的时候,会为当前正在创建的bean的标识符放到bean池中,待该bean创建成功后会从池中移除该bean标识符,基于这个原理,当创建A bean的时候,(会到池中查询是否本身的标识符已存在,不存在)会到会将A的标识符放到池中,A发现依赖B,则创建B bean,当创建B bean的时候(会到池中查询是否本身的标识符已存在,不存在)将B bean的标识符放到池中,B发现要依赖C,则创建C bean,当创建C bean的时候(会到池中查询是否本身的标识符已存在,不存在)将C bean的标识符放到池中,C发现需依赖A,则创建A,这时候发现A的创建标识符在池中(表示A正在创建中),则发现有循环依赖。

二、spring如何解决循环依赖

1.构造器的循环依赖 —无法解决

Caused by: org.springframework.beans.factory.BeanCurrentlyInCreationException:

在这里插入图片描述
springboot项目中检测到有构造器循环依赖,项目都不让起起来。

2.setter循环依赖(适用场景只有单例)

我们知道,当Spring创建单例对象主要分为三步,

1:调用构造器实例化
2:填充属性
3:初始化

因此循环依赖主要发生在第一、第二步,也就是构造器循环依赖和field循环依赖。所以,Spring先用构造器实例化Bean对象,将实例化结束的对象(此时该bean还未进行初始化的第二和第三步,但至少能用了)放到一个缓存中(提前暴露一个单例对象工厂),该工厂提供获取这个未设置属性的实例化对象的引用方法。根据上述例子,当Spring实例化了A、B、C后,紧接着会去设置对象的属性,此时A依赖B,就会去Map中取出存在里面的单例B对象,以此类推,解决循环的问题。以上也能解释为何构造器依赖无法解决,因为构造器依赖无法提供一个至少可用的bean。

此外Spring创建对象时涉及到以下三级缓存:
singletonFactories : 单例对象工厂的cache
earlySingletonObjects :提前暴光的单例对象的Cache
singletonObjects:单例对象的cache
这里先记录一下,回头有空再深入研究下。

总结

尽快Spring能解决Setter注入循环依赖,但是我们在编码过程中尽量避免这种情况,可以在代码review时使用工具检测写的代码是否有巡逻依赖,尽量保持项目代码清爽整洁,写代码设计过程中保持一点洁癖的工匠精神。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值