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

Spring如何解决项目中的循环依赖问题?

目录

什么是循环依赖?

如何解决?

采用两级缓存解决

需要AOP的Bean的循环依赖问题?

三级缓存解决


什么是循环依赖?

循环依赖就是Spring在初始化Bean时两个不同的Bean你依赖我,我依赖你的情况

例如A依赖B,B依赖A,当IoC容器初始化A时,发现它依赖于B,然后去创建B,创建B的时候又发现B依赖于A,而容器中不存在A,如果不想办法解决,这就会陷入死循环

例如下面这个代码,就是典型的循环依赖

// Spring 配置类,启用组件扫描
@Configuration
@ComponentScan
class AppConfig {
}// Author 服务类,依赖 BookService
@Service
class AuthorService {@AutowiredBookService bookService;
}// Book 服务类,依赖 AuthorService
@Service
class BookService {@AutowiredAuthorService authorService;
}// 程序入口类,测试循环依赖注入
public class SpringCircularDependencySingleClass {public static void main(String[] args) {ApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext(AppConfig.class);BookService bookService = (BookService) annotationConfigApplicationContext.getBean("bookService");System.out.println(bookService.authorService);AuthorService authorService = (AuthorService) annotationConfigApplicationContext.getBean("authorService");System.out.println(authorService.bookService);}
}    

运行这个项目,会发现它是正常运行的,这就表示Spring在背后做了一些工作解决了循环依赖的问题

如何解决?

Spring是使用三级缓存的模式来解决循环依赖问题的,其实两级缓存也是能够解决一般的循环依赖问题的,三级缓存主要是为了更好的解决带有AOP的Bean的循环依赖情况

这里先用两级缓存结构来初步阐述思想

采用两级缓存解决

Spring解决循环依赖的关键在于巧妙利用缓存机制。在Spring的实现中,主要涉及两个重要的Map:

singletonObjects:这是一个单例池,存放的是经历了完整Spring生命周期的Bean实例。这些Bean的所有依赖都已成功填充,处于完全可用状态。

earlySingletonObjects:该Map用于存放提前暴露出来的Bean对象。这些Bean刚刚创建完成,但尚未经历完整的Spring生命周期,其依赖尚未填充完毕

假设此时有两个Bean分别叫A、B,它们互相依赖

解决循环依赖的具体步骤如下:

1.先创建A的实例对象,在A的依赖注入之前,将A的早期对象放入earlySingletonObjects中去,然后开始给A注入依赖,发现依赖于B(此时两级缓存中都没有B),于是转去创建B

2.创建B的实例对象,将B的早期对象放入earlySingletonObjects,然后给B注入依赖,发现B依赖于A,于是去缓存中查找符合条件的Bean

3.先从singletonObjects中查找,发现没有,然后去earlySingletonObjects查找,发现存在A的早期对象,于是返回这个早期对象

4.将A注入到B中,然后将B放入singletonObjects中去

5.这个时候A可以从singletonObjects中获取B的实例,然后将完整的A放入singletonObjects中,循环依赖问题得以解决

需要AOP的Bean的循环依赖问题?

当一个Bean需要使用增强时,我们需要的是它的代理对象而不是它的原型对象,这个时候简单的两级缓存结构并不能很好的解决这个问题,所以Spring选择了三级缓存结构来解决

(两级缓存的解决思路是,在将早期对象放入earlySingletonObjects中前,先判断一下该对象是否需要AOP,如果需要的话生成该对象的代理对象放入earlySingletonObjects

但是!Spring的理念是尽量的把AOP的部分放到构造Bean的后期解决,而不是上来就直接生成一个代理对象,而且过早的生成代理对象也会额外造成空间和时间的消耗)

三级缓存解决

Spring引入了一个新的Map singletonFactories 来解决这个问题。 singletonFactories 存放的是 ObjectFactory 类型的工厂方法。当创建完对象后,并不立即进行AOP增强,而是将获取该对象的工厂方法放入 singletonFactories 。当发生循环依赖需要获取对象时,如果从 earlySingletonObjects 中无法获取到合适的对象,就从 singletonFactories 中取出工厂方法并执行,从而获取经过AOP增强后的对象。

相关文章:

Spring如何解决项目中的循环依赖问题?

目录 什么是循环依赖? 如何解决? 采用两级缓存解决 需要AOP的Bean的循环依赖问题? 三级缓存解决 什么是循环依赖? 循环依赖就是Spring在初始化Bean时两个不同的Bean你依赖我,我依赖你的情况 例如A依赖B&#xf…...

计算机系统---烤机(性能测评)

计算机烤机 一、烤机的定义与核心目的 烤机(Burn-in Test) 是通过对计算机硬件施加持续高负载,模拟极端运行环境,以验证硬件稳定性、性能极限、散热能力及潜在缺陷的测试方法。核心目标包括: 硬件稳定性验证&#x…...

Android开发过程中遇到的SELINUX权限问题

1、selinux权限一般问题 问题详情 log输出如下所示: 01-01 00:00:12.210 1 1 I auditd : type1107 audit(0.0:33): uid0 auid4294967295 ses4294967295 subju:r:init:s0 msg‘avc: denied{ set } for propertypersist.sys.locale pid476 uid1000 gid1000 scontext…...

[Java实战经验]链式编程与Builder模式

目录 链式编程Builder模式 链式编程 链式编程(Fluent AP)是一种编程风格,它通过在同一个对象上连续调用多个方法来执行一系列操作(让方法返回对象本身(return this))。这种风格的编程使代码更加…...

Windows系统docker desktop安装(学习记录)

目前在学习docker,在网上扒了很多老师的教程,终于装好了,于是决定再装一遍做个记录,省的以后再这么麻烦 一:什么是docker Docker 是一个开源的应用容器引擎,它可以让开发者打包他们的应用以及依赖包到一个…...

MIP-Splatting:全流程配置与自制数据集测试【ubuntu20.04】【2025最新版】

一、引言 在计算机视觉和神经渲染领域,3D场景重建与渲染一直是热门研究方向。近期,3D高斯散射(3D Gaussian Splatting)因其高效的渲染速度和优秀的视觉质量而受到广泛关注。然而,当处理大型复杂场景时,这种…...

怎样完成本地模型知识库检索问答RAG

怎样完成本地模型知识库检索问答RAG 目录 怎样完成本地模型知识库检索问答RAG使用密集检索器和系数检索器混合方式完成知识库相似检索1. 导入必要的库2. 加载文档3. 文本分割4. 初始化嵌入模型5. 创建向量数据库6. 初始化大语言模型7. 构建问答链8. 提出问题并检索相关文档9. 合…...

XCTF-web(三)

xff_referer 拦截数据包添加:X-Forwarded-For: 123.123.123.123 添加:Referer: https://www.google.com baby_web 提示:想想初始页面是哪个 查看/index.php simple_js 尝试万能密码,没有成功,在源码中找到如下&#xf…...

使用Python+xml+shutil修改目标检测图片和对应xml标注文件

使用Pythonxmlshutil修改目标检测图片文件名和对应xml标注文件: import os import glob import xml.etree.ElementTree as et import shutildef change_labels(source_dir):name_id 18001file_list glob.glob(os.path.join(source_dir, "*.xml"))print…...

How AI could empower any business - Andrew Ng

How AI could empower any business - Andrew Ng References 人工智能如何为任何业务提供支持 empower /ɪmˈpaʊə(r)/ vt. 授权;给 (某人) ...的权力;使控制局势;增加 (某人的) 自主权When I think about the rise of AI, I’m reminded …...

地理人工智能中位置编码的综述:方法与应用

以下是对论文 《A Review of Location Encoding for GeoAI: Methods and Applications》 的大纲和摘要整理: A Review of Location Encoding for GeoAI: Methods and Applications 摘要(Summary) 本文系统综述了地理人工智能(G…...

Verilog的整数除法

1、可变系数除法实现----利用除法的本质 timescale 1ns / 1ps // // Company: // Engineer: // // Create Date: 2025/04/15 13:45:39 // Design Name: // Module Name: divide_1 // Project Name: // Target Devices: // Tool Versions: // Description: // // Depe…...

C++ | STL之list详解:双向链表的灵活操作与高效实践

引言 std::list 是C STL中基于双向链表实现的顺序容器,擅长高效插入和删除操作,尤其适用于频繁修改中间元素的场景。与std::vector不同,std::list的内存非连续,但提供了稳定的迭代器和灵活的元素管理。本文将全面解析std::list的…...

React 把一系列 state 更新加入队列

把一系列 state 更新加入队列 设置组件 state 会把一次重新渲染加入队列。但有时你可能会希望在下次渲染加入队列之前对 state 的值执行多次操作。为此,了解 React 如何批量更新 state 会很有帮助。 开发环境:Reacttsantd 学习内容 什么是“批处理”以…...

【大模型理论篇】Search-R1: 通过强化学习训练LLM推理与利⽤搜索引擎

最近基于强化学习框架来实现大模型在推理和检索能力增强的项目很多,也是Deep Research技术持续演进的缩影。之前我们讨论过《R1-Searcher:通过强化学习激励llm的搜索能⼒》,今天我们分析下Search-R1【1】。 1. 研究背景与问题 ⼤模型(LLM&a…...

Google政策大更新:影响金融,新闻,社交等所有类别App

Google Play 4月10日 迎来了2025年第一次大版本更新,新政主要涉及金融(个人贷款),新闻两个行业。但澄清内容部分却使得所有行业都需进行一定的更新。下面,我们依次从金融(个人贷款),…...

什么时候触发full GC(发生场景)

文章目录 1. 老年代空间不足2. 分配担保失败3. 显式调用`System.gc()`4. 元空间/永久代空间不足5. CMS/G1的并发失败6. 空间分配担保机制7. 堆内存碎片化8. 其他场景总结回答在Java中,Full GC(全局垃圾回收)会回收整个堆内存(包括年轻代、老年代)以及元空间(或永久代)。…...

NO.93十六届蓝桥杯备战|图论基础-拓扑排序|有向无环图|AOV网|摄像头|最大食物链计数|杂物(C++)

有向⽆环图 若⼀个有向图中不存在回路,则称为有向⽆环图(directed acycline graph),简称 DAG 图 AOV⽹ 举⼀个现实中的例⼦:课程的学习是有优先次序的,如果规划不当会严重影响学习效果。课程间的先后次序可以⽤有向图表⽰ 在…...

每日文献(十三)——Part one

今天看的是《RefineNet: Iterative Refinement for Accurate Object Localization》。 目录 零、摘要 0.1 原文 0.2 译文 一、介绍 二、RefineNet A. Fast R-CNN B. Faster R-CNN C. RefineNet 训练 D. RefineNet 测试 零、摘要 0.1 原文 We investigate a new str…...

游戏引擎学习第225天

只能说太难了 回顾当前的进度 我们正在进行一个完整游戏的开发,并在直播中同步推进。上周我们刚刚完成了过场动画系统的初步实现,把开场动画基本拼接完成,整体效果非常流畅。看到动画顺利呈现,令人十分满意,整个系统…...

git提取出指定提交所涉及的所有文件

当需要提取出某次提交所修改过的所有的文件时&#xff0c;可以使用如下命令&#xff0c;该命令来自文心一言 mkdir temp_dir git diff-tree --no-commit-id --name-only -r <commit-hash> | xargs -I {} cp --parents {} temp_dir/--no-commit-id&#xff1a;不显示提交…...

Linux 使用Nginx搭建简易网站模块

网站需求&#xff1a; 一、基于域名[www.openlab.com](http://www.openlab.com)可以访问网站内容为 welcome to openlab ​ 二、给该公司创建三个子界面分别显示学生信息&#xff0c;教学资料和缴费网站&#xff0c;基于[www.openlab.com/student](http://www.openlab.com/stud…...

抖音ai无人直播间助手场控软件

获取API权限 若使用DeepSeek官方AI服务&#xff0c;登录其开发者平台申请API Key或Token。 若为第三方AI&#xff08;如ChatGPT&#xff09;&#xff0c;需通过接口文档获取访问权限。 配置场控软件 打开DeepSeek场控软件&#xff0c;进入设置界面找到“AI助手”或“自动化”…...

深度解析Redis过期字段清理机制:从源码到集群化实践 (二)

本文紧跟 上一篇 深度解析Redis过期字段清理机制&#xff1a;从源码到集群化实践 &#xff08;一&#xff09; 可以从redis合集中查看 八、Redis内核机制深度解析 8.1 Lua脚本执行引擎原理 Lua脚本执行流程图技术方案 ​​执行全流程解析&#xff1a;​ #mermaid-svg-X51Gno…...

TCP标志位抓包

说明 TCP协议的Header信息&#xff0c;URG、ACK、PSH、RST、SYN、FIN这6个字段在14字节的位置&#xff0c;对应的是tcp[13]&#xff0c;因为字节数是从[0]开始数的&#xff0c;14字节对应的就是tcp[13]&#xff0c;因此在抓这几个标志位的数据包时就要明确范围在tcp[13] 示例1…...

如何实现动态请求地址(baseURL)

需求: 在项目中遇到了需要实时更换请求地址,后续使用修改后的请求地址(IP) 例如:原ip请求为http://192.168.1.1:80/xxx,现在需要你点击或其他操作将其修改为http://192.168.1.2:80/xxx,该如何操作 tips: 修改后需要跳转( 修改了IP之前的不可使用,需要访问修改后的地址来操作 …...

封装一个搜索区域 SearchForm.vue组件

父组件 <template><div><SearchForm:form-items"searchItems":initial-values"initialValues"search"handleSearch"reset"handleReset"><!-- 自定义插槽内容 --><template #custom-slot"{ form }&qu…...

《ADVANCING MATHEMATICAL REASONING IN LAN- GUAGE MODELS》全文阅读

《ADVANCING MATHEMATICAL REASONING IN LAN- GUAGE MODELS: THE IMPACT OF PROBLEM-SOLVING DATA, DATA SYNTHESIS METHODS, AND TRAINING STAGES》全文阅读 提升语言模型中的数学推理能力&#xff1a;问题求解数据、数据合成方法及训练阶段的影响 \begin{abstract} 数学推…...

Day56 | 99. 恢复二叉搜索树、103. 二叉树的锯齿形层序遍历、109. 有序链表转换二叉搜索树、113. 路径总和 II

99. 恢复二叉搜索树 题目链接&#xff1a;99. 恢复二叉搜索树 - 力扣&#xff08;LeetCode&#xff09; 题目难度&#xff1a;中等 代码&#xff1a; class Solution {public void recoverTree(TreeNode root) {List<TreeNode> listnew ArrayList<>();dfs(root,…...

GPT - GPT(Generative Pre-trained Transformer)模型框架

本节代码主要为实现了一个简化版的 GPT&#xff08;Generative Pre-trained Transformer&#xff09;模型。GPT 是一种基于 Transformer 架构的语言生成模型&#xff0c;主要用于生成自然语言文本。 1. 模型结构 初始化部分 class GPT(nn.Module):def __init__(self, vocab…...