Spring 循环依赖详解
Spring 循环依赖详解
1. 引言
在Spring框架中,依赖注入(Dependency Injection, DI)是其核心功能之一,它通过配置来管理对象的创建和它们之间的依赖关系。然而,在复杂的应用程序中,开发人员有时会遇到循环依赖的问题,即Bean A依赖于Bean B,而Bean B又依赖于Bean A。如果不加以处理,这种情况会导致应用程序无法启动。在本文中,我们将深入探讨Spring循环依赖的原理、处理机制、最佳实践以及可能遇到的问题。
2. 什么是循环依赖?
循环依赖是指两个或多个Bean相互依赖,形成一个闭环。例如,假设有两个Bean,Bean A和Bean B:
- Bean A依赖于Bean B
- Bean B依赖于Bean A
这种依赖关系就形成了一个循环,导致Spring容器在初始化Bean时无法确定哪个Bean应先创建。
3. Spring循环依赖的分类
根据依赖注入的方式不同,循环依赖可以分为以下几种类型:
3.1 构造器循环依赖
构造器循环依赖是指两个或多个Bean通过构造器参数相互依赖。例如:
public class BeanA {private final BeanB beanB;public BeanA(BeanB beanB) {this.beanB = beanB;}
}public class BeanB {private final BeanA beanA;public BeanB(BeanA beanA) {this.beanA = beanA;}
}
3.2 属性循环依赖
属性循环依赖是指两个或多个Bean通过属性相互依赖。例如:
public class BeanA {private BeanB beanB;public void setBeanB(BeanB beanB) {this.beanB = beanB;}
}public class BeanB {private BeanA beanA;public void setBeanA(BeanA beanA) {this.beanA = beanA;}
}
4. Spring如何解决循环依赖
Spring框架通过三级缓存(三级缓存机制)来解决大多数情况下的循环依赖问题。三级缓存机制包括以下三个层次:
- 单例池(singletonObjects):用于存放完全初始化好的单例Bean。
- 早期曝光对象池(earlySingletonObjects):用于存放部分初始化完成的单例Bean,通常是通过提前暴露Bean引用来解决循环依赖。
- 三级缓存(singletonFactories):用于存放Bean工厂,以便在需要时创建Bean实例。
4.1 三级缓存机制详解
4.1.1 单例池(singletonObjects)
单例池是一个Map,用于存放完全初始化好的单例Bean。当Spring容器创建一个Bean时,会首先检查单例池中是否已经存在该Bean,如果存在则直接返回,否则继续创建。
4.1.2 早期曝光对象池(earlySingletonObjects)
早期曝光对象池是一个Map,用于存放部分初始化完成的单例Bean。当Spring容器检测到循环依赖时,会将部分初始化完成的Bean提前放入该池中,以便其他Bean能够引用。
4.1.3 三级缓存(singletonFactories)
三级缓存是一个Map,用于存放Bean工厂。Bean工厂是一个用于创建Bean实例的对象,当需要创建Bean实例时,Spring容器会从三级缓存中获取相应的Bean工厂,并通过它来创建Bean实例。
4.2 三级缓存的工作流程
- Spring容器创建Bean A,首先检查单例池中是否存在Bean A。
- 如果单例池中不存在Bean A,则检查早期曝光对象池中是否存在Bean A。
- 如果早期曝光对象池中也不存在Bean A,则从三级缓存中获取Bean A的工厂,并通过该工厂创建Bean A的实例。
- 创建Bean A实例的过程中,发现Bean A依赖于Bean B,因此开始创建Bean B。
- 创建Bean B的过程中,发现Bean B依赖于Bean A,此时检测到循环依赖。
- 将Bean A的实例放入早期曝光对象池中,以便Bean B可以引用。
- 继续完成Bean B的创建,并将其放入单例池中。
- 返回Bean B的实例,继续完成Bean A的创建,并将其放入单例池中。
通过上述流程,Spring容器可以成功处理大多数情况下的循环依赖。
5. 实践中的循环依赖
5.1 避免构造器循环依赖
构造器循环依赖是无法通过Spring的三级缓存机制解决的,因为构造器循环依赖会导致Spring无法实例化任何一个Bean。解决这种问题的方法有:
- 重构代码,避免循环依赖。
- 使用Setter方法注入而不是构造器注入。
5.2 使用@Lazy
注解
在某些情况下,可以使用@Lazy
注解来延迟Bean的初始化,从而避免循环依赖。例如:
public class BeanA {@Autowired@Lazyprivate BeanB beanB;
}public class BeanB {@Autowiredprivate BeanA beanA;
}
5.3 使用代理对象
使用代理对象也是解决循环依赖的一种方法。Spring AOP(面向切面编程)通过动态代理机制创建Bean的代理对象,可以在一定程度上缓解循环依赖的问题。
6. Spring循环依赖的潜在问题
尽管Spring可以通过三级缓存机制解决大多数情况下的循环依赖,但在实际开发中,循环依赖仍可能导致一些潜在的问题:
- 代码难以维护:循环依赖会使代码逻辑复杂,增加代码的维护难度。
- 性能问题:频繁使用三级缓存可能会影响性能,特别是在Bean数量较多的情况下。
- 潜在的内存泄漏:不正确的依赖管理可能导致内存泄漏,从而影响应用程序的稳定性。
7. 总结
Spring循环依赖是一个复杂的问题,理解其工作原理和解决机制对于开发高质量的Spring应用程序至关重要。通过合理的设计和最佳实践,可以有效避免和解决循环依赖,确保应用程序的稳定性和可维护性。
在本篇文章中,我们深入探讨了Spring循环依赖的概念、分类、解决机制以及实际开发中的最佳实践。希望通过这些内容,能够帮助读者更好地理解和应对Spring循环依赖问题。
8. 扩展阅读
对于想要进一步深入了解Spring循环依赖的读者,可以参考以下资料:
- 《Spring实战》:本书详细介绍了Spring框架的核心概念和使用方法。
- Spring官方文档:Spring官方文档是了解Spring框架最新特性和最佳实践的重要资源。
- GitHub上的Spring源码:通过阅读Spring源码,可以深入了解Spring内部的工作机制和实现细节。
通过这些扩展阅读,读者可以进一步提高对Spring循环依赖的理解和应对能力。
相关文章:
![](https://www.ngui.cc/images/no-images.jpg)
Spring 循环依赖详解
Spring 循环依赖详解 1. 引言 在Spring框架中,依赖注入(Dependency Injection, DI)是其核心功能之一,它通过配置来管理对象的创建和它们之间的依赖关系。然而,在复杂的应用程序中,开发人员有时会遇到循环…...
![](https://www.ngui.cc/images/no-images.jpg)
项目经理真的不能太“拧巴”
前期的项目经理经常是“拧巴”的,就是心里纠结、思路混乱、行动迟缓。对于每天需要面对各种挑战、协调各方资源、确保项目顺利进行的项目经理来说,这种“拧巴”不仅会让自己陷入内耗中,还会让项目出大问题。 项目计划总是改来改去࿰…...
![](https://img-blog.csdnimg.cn/img_convert/eade77740abb9a94d87449817c8d8577.png)
企业如何选择合适的CRM工具?除Salesforce之外的10大主流选择
对比salesforce,其他10款优秀CRM:纷享销客CRM、Zoho CRM、腾讯企点、销售易、企业微信 (WeCom)、Odoo CR、OroCRM、金蝶、用友CRM、EspoCRM 虽然Salesforce以其全面的功能和强大的市场占有率在海外收获了许多客户,但Salesforce在国内市场的接…...
![](https://img-blog.csdnimg.cn/img_convert/3ad834f6aa4cb6262ee0cc7b878a4684.png)
每年1-1.2万人毕业,男女比例约3:1,测绘工程的就业率如何
测绘工程,一个让人闻风丧胆的理科专业,虎扑评分4.2: 干过测绘的,苦不苦只有大家心里知道,带大家来感受一下,兄弟们的精神状态都十分美妙: 测绘专业到底是什么情况? PS.测绘分为本科…...
![](https://img-blog.csdnimg.cn/img_convert/249b1678454e42d83f5d1b00f6c9fa3a.png)
JimuReport 积木报表 v1.7.6 版本发布,免费的低代码报表
项目介绍 一款免费的数据可视化报表工具,含报表和大屏设计,像搭建积木一样在线设计报表!功能涵盖,数据报表、打印设计、图表报表、大屏设计等! Web 版报表设计器,类似于excel操作风格,通过拖拽完…...
![](https://www.ngui.cc/images/no-images.jpg)
“灵活就业者“超两亿人 游戏开发者如何破局?
随着“灵活就业”者数量突破两亿,我相信“寒气”已经传递到每一位普通人!对于游戏行业的“灵活就业”者,应当如何破局? 首先应该恭喜大家,选择了一个相对“稳健”的行业,无论大环境如何,游戏/软…...
![](https://img-blog.csdnimg.cn/direct/6958308f180845938027ec3d37b680d8.png)
MySQL事务与存储引擎
一、事务的概念 是一种机制、一个操作序列,包含了一组数据库操作命令,并且把所有的命令作为一个整体一起向系统提交或撤销操作请求,即这一组数据库命令要么都执行,要么都不执行是一个不可分割的工作逻辑单元,在数据库…...
![](https://www.ngui.cc/images/no-images.jpg)
总是给数据库表字段设置默认值的好处
1、NOT NULL DEFAULT 的好处 在设计数据库表结构时,将字段设置为不能为空并设置默认值有以下几种好处: 1.1、数据完整性 通过设置字段不能为空,可以确保每条记录都包含必要的数据,从而保证了数据的完整性。例如,在用…...
![](https://img-blog.csdnimg.cn/direct/603b3459b0d549eca40c0fbc82d4e45a.png)
11.2 Go 常用包介绍
💝💝💝欢迎莅临我的博客,很高兴能够在这里和您见面!希望您在这里可以感受到一份轻松愉快的氛围,不仅可以获得有趣的内容和知识,也可以畅所欲言、分享您的想法和见解。 推荐:「stormsha的主页」…...
![](https://img-blog.csdnimg.cn/direct/4edc25bcaa6e4ee8aaaaca29907c3701.png)
Sqlite3数据库基本使用
一、基本概念 数据:能够输入计算机并能被计算机程序识别和处理的信息集合 数据库:长期存储在计算机内、有组织的、可共享的大量数据的集合 DBMS:位于用户与操作系统之间的一层数据管理软件,用于操纵和管理数据库 二、安装 在线…...
![](https://img-blog.csdnimg.cn/direct/70b015c5f44b4d74967b95a33ba281af.png)
实现贪吃蛇小游戏【简单版】
1. 贪吃蛇游戏设计与分析 1.1 地图 我们最终的贪吃蛇大纲要是这个样子,那我们的地图如何布置呢? 这里不得不讲⼀下控制台窗口的⼀些知识,如果想在控制台的窗口中指定位置输出信息,我们得知道该位置的坐标,所以首先介…...
![](https://www.ngui.cc/images/no-images.jpg)
uniapp实现内嵌其他网页的功能
一、用到的知识点 页面跳转页面间跳转,参数传递web-view使用 二、使用navigator 页面跳转。 navigator 组件类似HTML中的<a>组件,但只能跳转本地页面。目标页面必须在pages.json中注册。所以这么写是不行的: <navigator url&quo…...
![](https://www.ngui.cc/images/no-images.jpg)
【Ruby简单脚本01】查看wifi密码
脚本 # 使用io库 def get_cmd_result(cmd) IO.popen(cmd,:external_encoding>GBK).read.encode("utf-8") end def list_wifi wifi_pwds Hash.new # 获取所有wifi文件 o1 get_cmd_result("netsh wlan show profiles") # 获取所有匹配结果 …...
![](https://img-blog.csdnimg.cn/img_convert/047976793ef516c92fdb18a10c2beed9.png)
VSG/VSA 矢量信号模拟/分析软件
_Ceyear思仪 _ VSG/VSA 矢量信号模拟/分析软件 苏州新利通仪器仪表 在现代无线通信中,IQ调制属于标准配置,经常应用于通信系统的信号调制和解调环节。IQ调制的应用简化了通信设备的硬件结构,同时提高了频谱资源的利用效率,提…...
![](https://www.ngui.cc/images/no-images.jpg)
C++使用GDAL库完成tiff图像的合并
全色图 完整代码: #include "gdal_priv.h" #include "cpl_string.h" #include <vector> #include <algorithm> #include <iostream> #include <filesystem>using namespace std; namespace fs std::filesystem; vec…...
![](https://www.ngui.cc/images/no-images.jpg)
深入理解AQS:Java并发编程中的核心组件
目录 AQS简介AQS的设计思路AQS的核心组成部分 状态(State)同步队列(Sync Queue)条件队列(Condition Queue) AQS的内部实现 节点(Node)锁的获取与释放 独占锁共享锁 条件变量 AQS的应…...
![](https://img-blog.csdnimg.cn/direct/cd118c0f23db453296124bc785dd6072.png)
集合进阶:List集合
一.List集合的特有方法 1.Collection的方法List都继承了 2.List集合因为有索引,所以多了很多索引操作的方法。 3.add // 1.创建一个集合List<String> list new ArrayList<>(); // 2.添加元素list.add("aaa");list.add("bbb"…...
![](https://img-blog.csdnimg.cn/direct/82a3c0d0ebe94ceebcf06b199dcb795b.png)
el-table表头修改文字或者背景颜色,通过header-row-style设置样式
方式一 <el-table :header-cell-style"{text-align: center}" />方式二 <template><el-table :header-cell-style"tableHeaderColor" /> </template> <script> export default {methods: {tableHeaderColor ({row, column…...
![](https://img-blog.csdnimg.cn/direct/6d8d151cded2438ca00b66aecf76c38e.png)
web前端-CSS
CSS CSS概述: CSS是Cascading Style Sheets(级联样式表),是一种样式表语言,用于控制网页布局,外观(比如背景图片,图片高度,文本颜色,文本字体,高级定位等等) 可将页面的内容与样式分离开,样式放于单独的.css文件或者HTML某处 CSS是网页样式,HTML是网页…...
![](https://www.ngui.cc/images/no-images.jpg)
u8g2 使用IIC驱动uc1617 lcd 字符显示只显示上半部分,不显示下半部
使用u8g2 使用硬件iic驱动某些page为4个字节 带灰度的lcd显示屏幕的时候有时候只显示上半部,下半部不显示,例如uc1617等。 原因: 以uc1617为例,链接https://github.com/olikraus/u8g2/blob/master/csrc/u8x8_d_uc1617.c 在u8x8_d_uc1617_common方法中的case U8X8_MSG_DI…...
![](https://img-blog.csdnimg.cn/direct/485ad4c1278645a7abd5b9241bbb7a1e.png)
单片机第五季-第八课:STM32CubeMx和FreeRTOS
1,FreeRTOS背景介绍 RTOS简介: 实时操作系统,本用于追求实时性的嵌入式系统,典型:ucos/uclinux/vxworks; 特点:中断响应快、一般可嵌套中断、使用实地址、多任务; (实…...
![](https://img-blog.csdnimg.cn/direct/2dd2d00d70504936a820b14fc8e1cf97.png)
【Linux】进程控制1——进程创建和进程终止
1.进程创建 1.1.再谈fork 在linux中fork函数时非常重要的函数,它从已存在进程中创建一个新进程。新进程为子进程,而原进程为父进程。 #include <unistd.h> pid_t fork(void);//pid_t为整形 返回值:子进程中的fork()返回0ÿ…...
![](https://img-blog.csdnimg.cn/direct/220a8852f6dc4a6ba5dc2f73c24a4902.png)
计算机图形学入门16:曲线
1.曲线 曲线(Curves)在图形学中应用非常广泛,比如:相机的拍摄路径、物体的移动路径、动画曲线、矢量字体等。如下图所示,是使用曲线到矢量字体的应用,通过移动一些控制点来改变字体。 2.贝塞尔曲线 2.1 贝…...
![](https://img-blog.csdnimg.cn/7cca864db76b46f1ba479780b00752d9.png)
【Ruby基础01】windows和termux中搭建Ruby开发环境
windows下环境搭建 railsinstaller官方git地址 按照文档安装git、nodejs、yarn,安装教程百度一下。railsinstall可以从release页面下载最新版本4.1.0。 安装完成如下 安装RubyMine 下载RubyMine RubyMine下载地址 安装激活 下载文件,按照里面的流程…...
![](https://www.ngui.cc/images/no-images.jpg)
2406c++,iguana动态反射
原文 iguana是一个基于编译期反射的序化库,支持从结构序化到不同数据格式. iguana可序化一个C结构到json,xml,yaml和protobuf格式.这都是通过编译期反射实现的. 现在iguana也支持了动态反射,主要特征: 1,通过对象名创建对象实例 2,取对象所有字段名 3,根据字段名取字段值 4,根…...
![](https://www.ngui.cc/images/no-images.jpg)
干货分享——AB站帮你解决独立站收款难题
目前,国内已经有抖音、拼多多和淘宝平台推出“仅退款”售后服务,无疑是加剧了原本就在疯狂打价格战的国内电商的严峻现状,使得商家不得不担心被顾客“薅羊毛”。在国内电商环境严重“内卷”的情况下,拓宽海外市场不失为一大妙计。…...
![](https://www.ngui.cc/images/no-images.jpg)
C++继承与派生
1.基本知识 类的继承是新类从已有类那里获得特性,从已有的类产生新类的过程称为类的派生; 已有类称为基类或父类,派生出的新类则称为派生类或子类; 继承的功能: (1)使得基类与派生类之间建立…...
![](https://img-blog.csdnimg.cn/direct/103614c14c1046c4a9e9819f7e112c7c.jpeg)
Survival Animations
一套生存游戏的动画集,包括采集、建造、捕鱼、剥皮/鞣制、篝火等更多内容。 总动画数:89 建造/制作 30 篝火 28 饮水 3 水壶 3 觅食 2 治疗 3 空闲 1 原始捕鱼 7 剥皮 1 矛捕鱼 4 伐木 5 下载:Unity资源商店链接资源下载链接 效果图:...
![](https://www.ngui.cc/images/no-images.jpg)
Cargo 教程
Cargo 教程 1. 引言 Cargo 是 Rust 编程语言的包管理器和构建工具。它为 Rust 项目提供了依赖管理、编译和打包等功能。本教程将详细介绍 Cargo 的基本用法,帮助您快速上手 Rust 项目开发。 2. 安装 Cargo 在开始使用 Cargo 之前,您需要确保已经安装了 Rust 编程语言。Ru…...
![](https://img-blog.csdnimg.cn/direct/59951089d4584d91aa5f63d68292f63e.png)
linux中“PXE高效批量装机”
在大规模的 Linux 应用环境中,如 Web 群集、分布式计算等,服务器往往并不配备光驱设备,在这种情况下,如何为数十乃至上百台服务器裸机快速安装系统呢?传统的 USB光驱、移动硬盘等安装方法显然已经难以满足需求。 PXE …...
![](/images/no-images.jpg)
网站开发需要学多久/谷歌推广开户多少费用
选择排序(Selection sort)跟插入排序一样,也是O(n^2)的复杂度,这个排序方式也可以用我们的扑克牌来解释。 概念 桌面上有一堆牌,也是杂乱无章的,现在我们想将牌由小到大排序,如果使用选择排序来做ÿ…...
![](https://img-blog.csdnimg.cn/20181125175234658.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L0MyNjgxNTk1ODU4,size_16,color_FFFFFF,t_70)
济南网站建设百家号/优化大师最新版下载
文章目录一、实验设计1、滤波前的准备2、函数设计二、实验过程三、结果分析一、实验设计 实验前的准备:傅里叶变换及反变换 opencv示例解读。 1、滤波前的准备 进行傅里叶逆变换需要知道原复数的实部和虚部,但是傅里叶变换后的图像显示的是幅度谱&…...
![](/images/no-images.jpg)
做防水广告在哪个网站最好/夸克搜索网页版
第一步:对制品2D图及3D图的分析和消化,其内容包括以下几个方面: 1、制品的几何形状。 2、制品的尺寸、公差及设计基准。 3、制品的技术要求(即技术条件)。 4、制品所用塑料名称、缩水及颜色。 5、制品的表面要求。 第二步&am…...
![](/images/no-images.jpg)
地图素材如何做ppt模板下载网站/销售平台
干掉庞大的Binlog文件 想要恢愎数据库以前的资料,执行:show binlog events;屏幕就开始闪,闪的人眼花,心里烦(那有这么多没有用的破LOG^0^),还是删除一些去吧!1.查找binary logs mysql> show binary logs; --------------------------- | Log_name | File_size | -----…...
![](/images/no-images.jpg)
学校网站建设栏目设置/广告投放代理商加盟
Swift JSON 发展史 最开始的时候还是使用NSJSONSerialization转成字典和数组来使用!后来苹果用Swift重新实现了JSONSerialization可以避免用NSArray和NSDictionary来桥接,提高解析效率。随后很多三方JSON库相继出现,例如:SwiftyJS…...
![](https://img-blog.csdnimg.cn/img_convert/04246fdfe8958426b043c89ded0857f1.png)
镇巴作风建设网站/营销网站建设门户
pip install cython -e git://github.com/surfly/gevent.git1.0rc2#egggevent使用技巧Gevent库性能很高,但一直以来我都纠结在python的GIL模型导致的线程不能抢占多核资源上面。而启动多个python进程的这种利用多核的模式又需要增加前端负载均衡,比如lvs…...