- 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站: