Java面试八股之Spring如何解决循环依赖

avatar
作者
筋斗云
阅读量:0
  1. Spring如何解决循环依赖

在Spring框架中,循环依赖问题通常发生在两个或多个Bean相互依赖的情况下。Spring为了解决循环依赖问题,采用了不同的策略,这些策略主要取决于Bean的作用域以及依赖注入的方式。下面是一些关键点:

单例Bean的循环依赖

对于单例(Singleton)作用域的Bean,Spring采用了一种叫做三级缓存机制来解决循环依赖问题。这种机制涉及三个缓存:

一级缓存:singletonObjects,存储完全初始化完毕的Bean实例。

二级缓存:earlySingletonObjects,存储正在创建中的Bean的早期引用(Early Singleton)。

三级缓存:singletonFactories,存储正在创建中的Bean的工厂。

当Spring初始化一个Bean时,流程如下:

如果在singletonObjects(一级缓存)中找到了Bean实例,则直接返回。

否则,检查earlySingletonObjects(二级缓存),如果存在,则返回早期引用。

如果上述两步都未找到,则从singletonFactories(三级缓存)中获取工厂,创建Bean实例。

创建过程中,如果遇到依赖,会再次尝试从缓存中获取依赖的Bean实例。

如果依赖的Bean也在创建中,则将其早期引用放入earlySingletonObjects,然后返回给请求方继续执行初始化。

初始化完成后,将Bean实例放入singletonObjects,并从earlySingletonObjects和singletonFactories中移除。

构造器注入的循环依赖

对于通过构造器注入的循环依赖,Spring无法使用上述缓存机制来解决,因为构造器必须在创建对象时就提供所有参数,没有机会在创建过程中返回部分初始化的对象。在这种情况下,通常需要重构代码来打破循环依赖。

解决循环依赖的其他策略

除了上述机制,开发人员还可以采用以下策略来避免或解决循环依赖问题:

重构代码:重构代码以打破循环依赖,例如通过引入第三个Bean作为中介来传递信息。

使用@Lazy注解:将其中一个Bean标记为懒加载,这样它在真正需要时才被初始化,从而避免在启动时形成循环依赖。

构造器注入转为Setter注入:如果可行,可以将构造器注入改为setter注入,利用Spring的缓存机制。

使用自定义工厂方法:创建自定义的工厂Bean或工厂方法,以便更好地控制依赖关系的创建顺序。

总之,Spring通过其内部的缓存机制可以解决大部分基于setter注入的循环依赖问题,但对于构造器注入的循环依赖,通常需要代码层面的调整来解决。在设计系统架构时,应尽量避免复杂的循环依赖,以简化依赖管理和提高系统的可测试性和可维护性。

如果大家需要视频版本的讲解,欢迎关注我的B站:

广告一刻

为您即时展示最新活动产品广告消息,让您随时掌握产品活动新动态!