MST
星途 面试题库

面试题:Java Spring Boot依赖注入中的循环依赖问题及解决方案

描述在Java Spring Boot的依赖注入过程中,循环依赖是如何产生的?请给出至少两种解决循环依赖问题的方法,并解释其原理。
41.1万 热度难度
编程语言Java

知识考点

AI 面试

面试题答案

一键面试

循环依赖产生原因

在Spring Boot的依赖注入过程中,当两个或多个bean相互依赖,形成一个闭合的依赖环时,就会产生循环依赖。例如,Bean A依赖Bean B,而Bean B又依赖Bean A。在创建Bean A时,需要先实例化Bean B,但在实例化Bean B的过程中,又需要实例化Bean A,这样就陷入了死循环。

解决方法及原理

  1. 使用构造器注入结合@Lazy注解
    • 方法:在构造器注入时,对其中一方使用@Lazy注解。
    • 原理@Lazy注解会使被依赖的bean以代理的方式进行注入,延迟初始化。这样在初始化依赖环中的第一个bean时,不会立即尝试初始化其依赖的bean,而是在真正使用该依赖时才进行初始化,从而打破循环依赖。例如,假设Bean A构造器依赖Bean B,给Bean B的注入点添加@Lazy注解,在实例化Bean A时,不会马上实例化Bean B,而是创建一个代理对象,当Bean A真正使用到Bean B时,才去实例化Bean B。
  2. 使用@Autowired的setter方法注入
    • 方法:将构造器注入改为使用@Autowired注解的setter方法注入。
    • 原理:Spring容器在实例化bean时,会先实例化一个原始的bean对象(此时bean的属性还未填充),并将其提前暴露到singletonFactories缓存中。当其他bean需要依赖这个bean时,可以从缓存中获取到这个早期的bean引用,虽然此时其属性可能还未完全初始化,但不会导致循环依赖。例如,Bean A通过setter方法依赖Bean B,Bean B通过setter方法依赖Bean A。Spring先实例化Bean A并放入早期对象缓存,然后实例化Bean B,在填充Bean B的属性时,发现依赖Bean A,就从缓存中获取Bean A的早期引用,填充到Bean B中,接着继续填充Bean A的属性,这样就避免了循环依赖。