当前位置: 首页 > news >正文

关于Spring Bean之间的循环依赖

最近在做一个项目关于农田项目管理的,碰到了循环依赖问题(之前只在八股中见过),最近在开发GbzntProject项目时,就遇到了这样一个典型的循环依赖错误。本文将详细分析这个问题产生的原因、表现形式以及解决方案。

问题背景

在Spring Boot项目开发过程中,我们经常会遇到循环依赖(Circular Dependency)的问题。最近在开发GbzntProject项目时,就遇到了这样一个典型的循环依赖错误。本文将详细分析这个问题产生的原因、表现形式以及多种解决方案。

 一、问题现象

 错误信息


```
***************************
APPLICATION FAILED TO START
***************************Description:The dependencies of some of the beans in the application context form a cycle:gbzntFacilityController ↓gbzntFacilityServiceImpl 
┌─────┐
|  gbzntProjectServiceImpl (field private org.jeecg.gbznt.project.service.GbzntProjectInfoService org.jeecg.gbznt.project.service.impl.GbzntProjectServiceImpl.gbzntProjectInfoService)
↑     ↓
|  gbzntProjectInfoServiceImpl (field private org.jeecg.gbznt.project.service.IGbzntProjectService org.jeecg.gbznt.project.service.impl.GbzntProjectInfoServiceImpl.gbzntProjectService)
└─────┘Action:Relying upon circular references is discouraged and they are prohibited by default.
```

错误解读
从错误信息可以看出,存在以下循环依赖链:
1. `gbzntFacilityController` → `gbzntFacilityServiceImpl`
2. `gbzntProjectServiceImpl` → `gbzntProjectInfoServiceImpl` → `gbzntProjectServiceImpl`(形成循环)

 二、问题根源分析

 2.1 循环依赖的产生

查看相关代码,发现问题的根源在于:

@Service
public class GbzntProjectServiceImpl implements IGbzntProjectService {@Autowiredprivate GbzntProjectInfoService gbzntProjectInfoService; // 依赖ProjectInfoService// ...
}
```
@Service
public class GbzntProjectInfoServiceImpl implements GbzntProjectInfoService {@Autowiredprivate IGbzntProjectService gbzntProjectService; // 又依赖回ProjectService// ...
}
```

这样就形成了:  
`ProjectService` → `ProjectInfoService` → `ProjectService`的循环依赖链。

2.2 Spring Bean的创建过程

Spring创建Bean的过程大致如下:
1. 创建`ProjectService`实例
2. 发现需要注入`ProjectInfoService`依赖
3. 创建`ProjectInfoService`实例
4. 发现需要注入`ProjectService`依赖
5. 但`ProjectService`还在创建中,形成循环依赖
6. Spring抛出异常,禁止这种循环引用

 三、解决方案

方案:Setter注入 + @Lazy

@Service
public class GbzntProjectServiceImpl implements IGbzntProjectService {private GbzntProjectInfoService gbzntProjectInfoService;@Autowired@Lazypublic void setGbzntProjectInfoService(GbzntProjectInfoService gbzntProjectInfoService) {this.gbzntProjectInfoService = gbzntProjectInfoService;}
}
```

为什么可以

首先介绍一下spring的三级缓存

循环依赖发生在两个或两个以上的bean互相持有对方,形成闭环。

Spring框架允许循环依赖存在,并通过三级缓存解决大部分循环依赖问题:

​1.一级缓存:单例池,缓存已完成初始化的bean对象。​

2.二级缓存:缓存尚未完成生命周期的早期bean对象。

​3.三级缓存:缓存ObjectFactory,用于创建bean对象。

而这个@Lazy注解让Spring创建一个代理对象而不是真实对象,就是存在二级缓存中的代理对象

所以现在的加载逻辑为

  1. 创建ServiceA流程

    • 实例化ServiceA对象

    • 发现setServiceB方法有@Lazy注解

    • 注入一个ServiceB的代理对象(不是真实ServiceB实例)

    • ServiceA创建完成,放入单例池

  2. 创建ServiceB流程

    • 实例化ServiceB对象

    • 发现setServiceA方法有@Lazy注解

    • 注入一个ServiceA的代理对象(此时ServiceA已创建完成)

    • ServiceB创建完成,放入单例池

  3. 实际调用时

    • 当第一次调用serviceB的方法时

    • 代理对象会触发真实ServiceB的创建

    • 此时所有依赖都已就绪,不会出现循环依赖

 四、总结

循环依赖是Spring Boot项目中常见的问题,其根本原因在于不合理的设计和过度的耦合。通过本文的分析和解决方案,我们可以:

1. 理解循环依赖的产生机制:Spring Bean的创建过程和依赖注入机制
2. 掌握多种解决方:从代码重构到配置调整的各种方法
3. 遵循最佳实践:采用合理的架构设计和编码规范

http://www.dtcms.com/a/391901.html

相关文章:

  • pake将前端web项目打包成windows可安装文件
  • 低轨卫星应用:MCU、CANFD与DCDC芯片的集成解决方案
  • AI 编程Claude Code使用详细教程
  • vue3 下载文件方式(包括通过url下载文件并修改文件名称,和文件流下载方式)
  • 如何高效筛选海量文献,避免浪费时间?
  • heyday
  • Go语言结构体初始化全面指南与最佳实践
  • 神经网络学习笔记15——高效卷积神经网络架构GhostNet
  • Mysql的Exists条件子查询
  • 电脑系统windows10怎么合盘
  • 一文详解Stata回归分析
  • GPS 定位:连接时空的数字导航革命
  • Rust 特有关键字及用法
  • 关于C++游戏开发入门:如何从零开始实现一个完整的游戏项目!
  • OpenRank结合游戏及算法技术原理
  • 协方差矩阵、皮尔逊相关系数
  • Redis 三大架构模式详解:主从复制、哨兵、Cluster 搭建全指南
  • [x-cmd] 如何安全卸载 x-cmd
  • 整体设计 语言拼凑/逻辑拆解/词典缝合 之 3 词典缝合(“他”):显露词典编纂行列式项的 “自然”三“然”:自然本然/ 自然而然/自然实然
  • linux配置ssh,亲测简单可用
  • SNMP 模块化设计解析
  • 2025的Xmind自定义安装(实测版)
  • AI“闻香识酒”:电子鼻+机器学习开启气味数字化新纪元
  • Coze工作流拆解:成语故事类小红书图文批量创作全流程
  • PyQt6之进度条
  • 【AI编程】Trae配置rules与配置和使用一些目前比较好用的MCP
  • 音乐家不会被束缚,MusicGPT+cpolar让创作更自由
  • python笔记之面向对象篇(六)
  • Linux中处理nohup日志太大的问题
  • vLLM应该怎么学习