Spring-IOC
# Spring-IOC
# 循环依赖
- 面试题
- 解释一下Spring中的三级缓存
- 三级缓存是什么?三个Map有什么异同
- 什么是循环依赖?请你谈谈?看过Spring源码吗?一般说的Spring容器是什么?
- 如何检测是否存在循环依赖?实际开发中见过循环依赖的异常吗?
- 多例情况下,循环依赖问题为什么无法解决?
- 什么是循环依赖?
- 多个bean之间互相依赖,形成了一个闭环。比如,A依赖于B,B依赖于C,C依赖于A。(或AB互相依赖)

- 通常来说,如果问Spring是如何解决循环依赖的问题的,一定是指默认的单例Bean中,属性互相引用的场景。注:定义bean的时候,可以指定scope为singleton/prototype
- 多个bean之间互相依赖,形成了一个闭环。比如,A依赖于B,B依赖于C,C依赖于A。(或AB互相依赖)
- 两种注入方式对循环依赖的影响
- 循环依赖官网说明

- 结论
- 只要bean的注入方式是setter且singleton的就不会有循环依赖问题,Spring用三级缓存解决了。DefaultSingletonBeanRegistry

- 只要bean的注入方式是setter且singleton的就不会有循环依赖问题,Spring用三级缓存解决了。DefaultSingletonBeanRegistry
- 循环依赖官网说明
- Spring容器循环依赖报错演示BeanCurrentlyInCreationException
在Spring容器中注入依赖的对象有两种方式
- constructor
code
@Component public class ServiceA { private ServiceB serviceB; public ServiceA(ServiceB serviceB){ this.serviceB = serviceB; } } @Component public class ServiceB { private ServiceA serviceA; public ServiceB(ServiceA serviceA){ this.serviceA = serviceA; } } public class ClientConstructor { public static void main(String[] args) { //俄罗斯套娃,无穷无尽 new ServiceA(new ServiceB(new ServiceA(new ServiceB()))); } }1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20结论
- 构造器循环依赖是无法解决的
- setter
code
@Component public class ServiceA { private ServiceB serviceB; public void setServiceB(ServiceB serviceB){ this.serviceB = serviceB; } } @Component public class ServiceB { private ServiceA serviceA; public void setServiceA(ServiceA serviceA){ this.serviceA = serviceA; } } public class ClientSetter { public static void main(String[] args) { //成功注入 ServiceA serviceA = new ServiceA(); ServiceB serviceB = new ServiceB(); serviceA.setServiceB(serviceB); serviceB.setServiceA(serviceA); } }1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
- constructor
Spring IOC Case
默认单例(singleton)的场景是支持循环依赖的,不会报错
- applicationContext.xml
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd"> <bean id="a" class="com.jjc.mypratice.spring.ioc.circulardepend.A"> <property name="b" ref="b"/> </bean> <bean id="b" class="com.jjc.mypratice.spring.ioc.circulardepend.B"> <property name="a" ref="a"/> </bean> </beans>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18- bean
public class CircularDependBugTest { public static void main(String[] args) { ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml"); A a = applicationContext.getBean("a", A.class); B b = applicationContext.getBean("b", B.class); } }1
2
3
4
5
6
7
8- 执行结果

原型(prototype)的场景是不支持循环依赖的,会报错
- applicationContext.xml
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd"> <bean id="a" class="com.jjc.mypratice.spring.ioc.circulardepend.A" scope="prototype"> <property name="b" ref="b"/> </bean> <bean id="b" class="com.jjc.mypratice.spring.ioc.circulardepend.B" scope="prototype"> <property name="a" ref="a"/> </bean> </beans>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18- bean
public class CircularDependBugTest { public static void main(String[] args) { ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml"); A a = applicationContext.getBean("a", A.class); B b = applicationContext.getBean("b", B.class); } }1
2
3
4
5
6
7
8- 执行结果

结论
- singleton可以解决循环依赖
- 循环依赖debug
- 实例化/初始化
- 实例化create
- 内存中开辟一块空间
- 类比,租赁/买好房子,还没置办家具/装修
- 初始化populate
- 完成属性的赋值
- 类比,置办家具/装修
- 实例化create
- 3个Map和4个方法

- A/B对象在三级缓存中的迁移
- Debug

- 实例化/初始化
- 总结----Spring是如何解决循环依赖的
- 如何解决

- 流程

- 如何解决
编辑 (opens new window)
上次更新: 2024/05/24, 11:36:46