常见问题
- 你解释一下 spring 中的三级缓存?
- 三级缓存分别是什么?三个 Map 有什么异同?
- 什么是循环依赖?请谈谈?你看过 spring 的源码吗?一般我们说的是 spring 容器是什么?
- 多例的情况下,循环依赖问题为什么无法解决?
什么是循环依赖?
多个 bean 之间相互依赖,形成闭环。 比如:A 依赖于 B, B 依赖于 C , C 依赖于 A示例代码
public class T1 { class A { B b; } class B { C c; } class C { A a; } }
比如:A 依赖于 B, B 依赖于 C , C 依赖于 A
通常来说,如果问 Spring 容器内部如何解决循环依赖,一定是指默认的单例 Bean 中, 属性相互引用的场景。
@Component public class A { @Autowired private B b; } @Component public class B { @Autowired private C c; } @Component public class C { @Autowired private A a; }
循环依赖说明
官方说明
参考官方说,下面会有官网链接
官网链接:docs.spring.io/spring-fram…
结论
构造方法注入:不支持循环依赖。结论:我们 AB 循环依赖问题。只要 A 的方式是 setter 且 singleton 就不会有循环依赖问题。
BeanCurrentlyInCreationException
循环依赖异常的定义如下所示,如果出现循环依赖,我们在启动/运行过程中会报这个错误。
依赖注入的两种方式
方式一:构造器方式注入依赖
@Component public class ServiceA{ private ServiceB serviceB; public ServiceA(ServiceB serverB) { this.serivceB = serviceB; } } @Component public class ServiceB{ private ServiceA serviceA; public ServiceB(ServiceA serviceA) { this.serviceA = serviceA; } }
构造器循环依赖是无法解决的,你想让构造器注入支持循环依赖,是不可能的。
方式二:以 set 方式注入依赖
@Component public class ServiceA{ private ServiceB serviceB; public setServiceB(ServiceB serverB) { this.serivceB = serviceB; } } @Component public class ServiceB{ private ServiceA serviceA; public setServiceB(ServiceA serviceA) { this.serviceA = serviceA; } }
案例演示(基于 Spring 容器的循环依赖)
普通的 Java 基础编码A 类、B 类
@Data public class A{ private B b; public A() { System.out.println("----- A create success"); } } @Data public class B{ private a a; public B() { System.out.println("------ B create success"); } }
循环依赖解决
A a = new A(); B b = new B(); a.setB(b); b.setA(a);
基于 Spring 容器的循环依赖
- 默认的单例(singleton)的场景是支持循环依赖的,不报错
- 原型(prototype)的场景是不支持循环依赖的, 会报错
代码演示
- 循环依赖代码
@Component @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE) public class A { @Autowired private B b; } @Component public class B { @Autowired private A a; }
- 默认单例,修改为原型
// 增加注解 @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
- 一段测试程序
class BTest { @Configuration @Import({A.class, B.class}) public static class TestConfig { } @Test public void currentlyincreation() { AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(TestConfig.class); // 这里要获取 bean 一下,如果不去主动获取,可能是由于惰性加载没有执行,不会报错 A a = applicationContext.getBean(A.class); System.out.println(a); } }
- 循环依赖异常