【spring】如何解决循环依赖

简介: 【spring】如何解决循环依赖

概念

Spring循环依赖是指两个或多个Bean之间相互依赖,形成了双向依赖关系,导致Spring无法正确地完成Bean的创建和初始化。

Spring框架为了解决循环依赖问题,采用了三级缓存的方式来解决。

第一级缓存:单例池中的三级缓存

每个Bean在被创建时,会先放入单例池中的一级缓存(singletonObjects),如果这个Bean被其他的Bean依赖,那么会先从一级缓存中获取,如果一级缓存中还没有,那么就会继续创建。

第二级缓存:提前暴露对象解决循环依赖

如果一个Bean被创建出来,但是其中某个属性引用的是当前Bean类型的另一个Bean,这时候Spring会将当前Bean提前暴露,放入到单例池中的二级缓存(earlySingletonObjects)中,这样在创建该属性引用的Bean时,就可以直接从二级缓存中获取,避免了创建中的循环依赖问题。

第三级缓存:解决循环依赖

如果Spring在从一级和二级缓存中获取Bean时还是出现了循环依赖,那么Spring就会放弃从缓存中获取Bean,而创建一个新的Bean,并将其放入到单例池中的三级缓存(singletonFactories)中,这个Bean创建完成后,Spring会对它进行属性填充,并将其放入到一级缓存中,最终完成Bean的创建和初始化。

需要注意的是,循环依赖是一个比较容易出现的问题,虽然Spring采用了三级缓存的方式解决了这个问题,但在实际项目中还是要尽可能避免循环依赖的出现。

报错

binanceAggTradeListener defined in file [F:\git\eladmin\quantify-op-be\quantify-op-be\quantify-system\target\classes\me\zhengjie\listener\BinanceAggTradeListener.class]

orderRecordServiceImpl

┌─────┐

| commonServiceImpl

↑ ↓

| copyTradingServiceImpl

└─────┘

分析

因为有3个服务的代码一致,所以抽取了一个公共方法,公共方法中也有需要调用其中一个服务的方法,所以就出现了循环依赖

方案

  1. 使用 setter/field 方法注入
    上面说到,只有构造方法是在上下文加载时就要求被注入,容易出现依赖循环。所以可以用其他的方式进行依赖注入,setter 和 field 方法注入与构造方法不同,它们不会在创Bean时就注入依赖,而是在被需要时才注入。
private CopyTradingService copyTradingService;

2.解决Spring 循环依赖的一个简单方法就是对一个Bean使用延时加载。也就是说:这个Bean并没有完全的初始化完,实际上他注入的是一个代理,只有当他首次被使用的时候才会被完全的初始化

  @Autowired
    public CommonServiceImpl(@Lazy CopyTradingService copyTradingService) {
        this.copyTradingService= copyTradingService;
    }

3.在你注入bean时,在互相依赖的两个bean上加上@Lazy注解也可以

@Autowired     
 
@Lazy      
 
private ClassA classA; 
 
 
@Autowired 
 
@Lazy      
 
private ClassB classB; 

总结

循环依赖是Spring框架中一个常见的问题,它发生在两个或更多的bean相互依赖,导致Spring无法正确地创建它们。解决循环依赖的问题需要理解Spring的依赖注入机制以及bean的生命周期。

首先,Spring的依赖注入有两种方式:构造器注入和属性注入。构造器注入是将依赖对象作为构造函数的参数传递给bean,而属性注入则是将依赖对象赋值给bean的属性。当两个bean相互依赖时,构造器注入更容易解决循环依赖的问题,因为可以在构造对象时完成依赖的注入。

解决循环依赖的几种方法:

使用构造器注入:通过将依赖对象作为构造函数的参数传递给bean,可以避免属性依赖导致的循环引用。

使用setter注入:如果不能修改源代码,可以使用setter注入方式,将依赖对象赋值给bean的属性。但是这种方式容易产生循环依赖的问题,因为setter方法是在对象创建后才被调用。

使用@Lazy注解:Spring提供了@Lazy注解,可以将依赖对象的创建延迟到真正使用时。这样可以在一定程度上解决循环依赖的问题,但会增加系统的复杂性和性能开销。

使用接口:如果两个bean之间存在循环依赖,可以尝试将它们抽象为一个接口,通过接口进行通信。这样可以避免直接依赖具体类导致的循环引用问题。

重构代码:从设计层面解决循环依赖的问题是最理想的方案。可以考虑将循环依赖的部分提取出来,作为一个独立的类或者服务,从而消除原始代码中的循环依赖。

总之,解决循环依赖的问题需要结合具体的业务场景和代码结构,选择合适的方法进行优化。同时,要注意代码的可读性和可维护性,避免过度设计导致代码复杂度增加。

目录
相关文章
|
2月前
|
缓存 架构师 Java
图解 Spring 循环依赖,一文吃透!
Spring 循环依赖如何解决,是大厂面试高频,本文详细解析,建议收藏。关注【mikechen的互联网架构】,10年+BAT架构经验倾囊相授。
图解 Spring 循环依赖,一文吃透!
|
1月前
|
存储 缓存 Java
Spring面试必问:手写Spring IoC 循环依赖底层源码剖析
在Spring框架中,IoC(Inversion of Control,控制反转)是一个核心概念,它允许容器管理对象的生命周期和依赖关系。然而,在实际应用中,我们可能会遇到对象间的循环依赖问题。本文将深入探讨Spring如何解决IoC中的循环依赖问题,并通过手写源码的方式,让你对其底层原理有一个全新的认识。
63 2
|
4月前
|
缓存 Java 开发工具
Spring是如何解决循环依赖的?从底层源码入手,详细解读Spring框架的三级缓存
三级缓存是Spring框架里,一个经典的技术点,它很好地解决了循环依赖的问题,也是很多面试中会被问到的问题,本文从源码入手,详细剖析Spring三级缓存的来龙去脉。
240 24
|
3月前
|
缓存 Java Spring
源码解读:Spring如何解决构造器注入的循环依赖?
本文详细探讨了Spring框架中的循环依赖问题,包括构造器注入和字段注入两种情况,并重点分析了构造器注入循环依赖的解决方案。文章通过具体示例展示了循环依赖的错误信息及常见场景,提出了三种解决方法:重构代码、使用字段依赖注入以及使用`@Lazy`注解。其中,`@Lazy`注解通过延迟初始化和动态代理机制有效解决了循环依赖问题。作者建议优先使用`@Lazy`注解,并提供了详细的源码解析和调试截图,帮助读者深入理解其实现机制。
96 1
|
4月前
|
缓存 Java Spring
手写Spring Ioc 循环依赖底层源码剖析
在Spring框架中,IoC(控制反转)是一个核心特性,它通过依赖注入(DI)实现了对象间的解耦。然而,在实际开发中,循环依赖是一个常见的问题。
56 4
|
5月前
|
存储 缓存 Java
面试问Spring循环依赖?今天通过代码调试让你记住
该文章讨论了Spring框架中循环依赖的概念,并通过代码示例帮助读者理解这一概念。
面试问Spring循环依赖?今天通过代码调试让你记住
|
5月前
|
缓存 Java Spring
spring如何解决循环依赖
Spring框架处理循环依赖分为构造器循环依赖与setter循环依赖两种情况。构造器循环依赖不可解决,Spring会在检测到此类依赖时抛出`BeanCurrentlyInCreationException`异常。setter循环依赖则通过缓存机制解决:利用三级缓存系统,其中一级缓存`singletonObjects`存放已完成的单例Bean;二级缓存`earlySingletonObjects`存放实例化但未完成属性注入的Bean;三级缓存`singletonFactories`存放创建这些半成品Bean的工厂。
|
5月前
|
Java Spring 容器
循环依赖难破解?Spring Boot神秘武器@RequiredArgsConstructor与@Lazy大显神通!
【8月更文挑战第29天】在Spring Boot应用中,循环依赖是一个常见问题。当两个或多个Bean相互依赖形成闭环时,Spring容器会陷入死循环。本文通过对比@RequiredArgsConstructor和@Lazy注解,探讨它们如何解决循环依赖问题。**@RequiredArgsConstructor**:通过Lombok生成包含final字段的构造函数,优先通过构造函数注入依赖,简化代码但可能导致构造函数复杂。**@Lazy**:延迟Bean的初始化,直到首次使用,打破创建顺序依赖,增加灵活性但可能影响性能。根据具体场景选择合适方案可有效解决循环依赖问题。
201 0
|
6月前
|
缓存 Java 开发者
Spring循环依赖问题之Spring循环依赖如何解决
Spring循环依赖问题之Spring循环依赖如何解决
|
5月前
|
前端开发 Java 测试技术
单元测试问题之在Spring MVC项目中添加JUnit的Maven依赖,如何操作
单元测试问题之在Spring MVC项目中添加JUnit的Maven依赖,如何操作