spring循环依赖
Spring中的循环依赖是指在Spring容器中,两个或多个Bean之间相互依赖,形成了一个闭环的依赖关系。以下是关于Spring循环依赖的详细介绍:
循环依赖的类型
- 构造器循环依赖:Bean A的构造函数中需要注入Bean B,而Bean B的构造函数中又需要注入Bean A,这种情况在Spring中是无法解决的,会导致
BeanCurrentlyInCreationException
异常。因为构造器注入是在Bean实例化的过程中进行的,在这种循环依赖下,Spring无法完成Bean的实例化。 - 字段注入循环依赖:Bean A通过字段注入的方式依赖Bean B,而Bean B又通过字段注入依赖Bean A。
- setter方法循环依赖:Bean A通过setter方法注入Bean B,Bean B又通过setter方法注入Bean A。这种情况与字段注入类似,Spring容器在处理时也会面临挑战。
Spring解决循环依赖的原理
Spring通过三级缓存来解决循环依赖问题,这三级缓存分别是:
- 一级缓存:
singletonObjects
,用于存储已经创建好的单例Bean对象,是一个ConcurrentHashMap
。当Spring创建好一个单例Bean后,会将其放入这个缓存中,以后再获取该Bean时,直接从这里获取。 - 二级缓存:
earlySingletonObjects
,用于存储早期暴露的Bean对象。在Bean的创建过程中,当Bean完成实例化但还未进行属性填充等后续操作时,会将其提前放入二级缓存。这个缓存主要是为了解决循环依赖时,让其他Bean能够提前获取到正在创建中的Bean的引用。 - 三级缓存:
singletonFactories
,用于存储Bean工厂对象。在创建Bean时,如果发现该Bean可能存在循环依赖,会将一个能够生成该Bean的工厂对象放入三级缓存。其他Bean在需要依赖该Bean时,可以通过这个工厂对象获取到早期的Bean引用。
在Spring创建Bean的过程中,会按照以下步骤利用三级缓存来处理循环依赖:
- 首先从一级缓存
singletonObjects
中获取Bean,如果能获取到,说明Bean已经创建完成,直接返回。 - 如果一级缓存中没有,就从二级缓存
earlySingletonObjects
中获取。如果能获取到,说明这是一个早期暴露的Bean,也直接返回。 - 如果二级缓存中也没有,就从三级缓存
singletonFactories
中获取对应的Bean工厂。如果有,就通过工厂获取早期的Bean引用,并将其放入二级缓存,同时从三级缓存中移除。 - 如果三级缓存中也没有,就开始创建Bean。在创建过程中,如果发现Bean存在依赖其他Bean的情况,就会先去创建依赖的Bean,然后再回来继续完成当前Bean的创建。在创建依赖的Bean时,同样会按照上述步骤检查缓存,处理可能存在的循环依赖。
示例代码
以下是一个简单的Spring循环依赖的示例代码:
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; @Component public class A { @Autowired private B b; public A() { System.out.println("A的构造函数"); } public void doSomething() { System.out.println("A执行某个操作"); } } @Component public class B { @Autowired private A a; public B() { System.out.println("B的构造函数"); } public void doSomething() { System.out.println("B执行某个操作"); } }
在上述代码中,A
类依赖B
类,B
类又依赖A
类,形成了循环依赖。如果在Spring项目中运行这段代码,Spring容器会通过三级缓存机制来解决这个循环依赖问题,确保A
和B
都能正确创建和注入。
注意事项
- 多例Bean的循环依赖:Spring默认是不支持多例Bean的循环依赖的,因为多例Bean在每次获取时都会创建一个新的实例,无法像单例Bean那样通过缓存来解决循环依赖。
- 延迟加载:可以使用
@Lazy
注解来延迟Bean的加载,对于一些可能存在循环依赖但又不是在启动时就必须使用的Bean,可以通过延迟加载来避免循环依赖问题在启动时就暴露出来。
职保镖-扶你上马 文章被收录于专栏
知识分享,交天下朋友,扶你上马,送你一层,职业规划,面试指导、高薪谈判、背调辅助