【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]

orderServiceImpl defined in file [F:\git\eladmin\quantify-op-be\quantify-op-be\quantify-system\target\classes\me\zhengjie\modules\system\service\impl\OrderServiceImpl.class]

orderRecordServiceImpl
┌─────┐
| commonServiceImpl
↑ ↓
| copyTradingServiceImpl
└─────┘

分析

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

方案

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

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

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

总结

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

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

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

使用构造器注入:通过将依赖对象作为构造函数的参数传递给bean,可以避免属性依赖导致的循环引用。
使用setter注入:如果不能修改源代码,可以使用setter注入方式,将依赖对象赋值给bean的属性。但是这种方式容易产生循环依赖的问题,因为setter方法是在对象创建后才被调用。
使用@Lazy注解:Spring提供了@Lazy注解,可以将依赖对象的创建延迟到真正使用时。这样可以在一定程度上解决循环依赖的问题,但会增加系统的复杂性和性能开销。
使用接口:如果两个bean之间存在循环依赖,可以尝试将它们抽象为一个接口,通过接口进行通信。这样可以避免直接依赖具体类导致的循环引用问题。
重构代码:从设计层面解决循环依赖的问题是最理想的方案。可以考虑将循环依赖的部分提取出来,作为一个独立的类或者服务,从而消除原始代码中的循环依赖。
总之,解决循环依赖的问题需要结合具体的业务场景和代码结构,选择合适的方法进行优化。同时,要注意代码的可读性和可维护性,避免过度设计导致代码复杂度增加。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/156290.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Mac如何搭建Vue项目

目录 一、安装node 二、安装NPM 1、本地安装和全局安装 2、通过Node.js官方安装程序安装 3、通过Homebrew安装 三、NPM常用命令 1、查看模块的版本号 2、安装指定版本 3、卸载模块 4、更新模块 5、查看模块信息 6、查看模块地址 7、更新命令 8、卸载NPM 四、安装…

设计模式 - 概览

一、概念 分为三大类、23中具体设计模式。 类型原理具体模式创建型封装了具体类的信息,隐藏了类的实例化过程。 单例模式(Singleton) 工厂方法模式(Factory Method) 抽象工厂模式(Abstract Factory&#xf…

观光奶牛 (01分数规划、负环)

01分数规划问题:类似于观光奶牛这个题中的,求的路径上的点权值和与边权值和的商最大最小。 当前问题的推到如下: 该问题其实可以用二分图来解决, 在不断的二分答案中获取符合条件的最大值。然后问题就转化为如何是否存在和为mid的…

Vue3中的pinia使用,入门教程

文章目录 文章目录 pinia组成部分 pinia使用流程 注意Store获取到后不能解构,否则失去响应式 一、pinia原理? 功能:管理全局共享数据,pinia与vuex功能一样优势:pinia相对于vuex增加了对ts的支持,对响应式的…

程序员如何“升级打怪”?我用了这几个“歪瓜”!

不会吧?不会吧?计算机本命专业出身、以及半路出家的,混了几年了,还在新手村?对得起这几年摸的鱼? 思考一下:如何从小白一跃为大师,从此走上人生巅峰、迎娶白富美?变强只…

Java --- JVM之垃圾回收相关知识概念

目录 一、System.gc() 二、内存溢出与内存泄漏 2.1、内存溢出 2.2、内存泄漏 三、Stop the world 四、垃圾回收的并行与并发 4.1、并发 4.2、并行 4.3、并行 vs 并发 4.4、垃圾回收的并发与并行 五、安全点与安全区域 5.1、安全点 5.2、安全区域 六、引用 6.1…

3.基于多能互补的热电联供微网优化运行复现(matlab代码)

0.代码链接 基于多能互补的热电联供微电网/综合能源系统优化运行(Matlab程序Yalmip+Cplex求解)_工业综合能源系统资源-CSDN文库 2. 主要内容:代码主要做的是多能互补的热电联供型微网优化运行模型,在需求侧对负荷类型…

hive数据库将非分区表数据迁移到分区表

文章目录 一、非分区表数据迁移到分区表 一、非分区表数据迁移到分区表 业务运行一段时间后非分区表的数据量非常大,需要创建一张分区表并将数据迁移到分区表中。 原表建表语句: create table user(id String default null comment 主键id,name St…

c# 文件操作

文件操作 namespace demo1;class proj {/// <summary>///文件&#xff1a;///注册表是Micrsoft windows 中的一个重要的数据库&#xff0c;用于存储系统和应用恒旭的设置信息///主要了解文件和注册表的创建、打开、读取、写入、修改、删除/// </summary>//////文件…

Android Studio 引入Xui框架-简单应用

Android Studio Flamingo | 2022.2.1 Patch 2 Android 11开发、Gradle Version 8.0、 jdk17 源代码&#xff1a;GitHub - xuexiangjys/XUI: &#x1f48d;A simple and elegant Android native UI framework, free your hands! (一个简洁而优雅的Android原生UI框架&#xff…

【Chrony】一个多功能的NTP实现

在现代的计算机系统中&#xff0c;准确的时间同步对于许多关键应用和系统的正常运行至关重要。Linux操作系统提供了多种时间同步工具&#xff0c;其中Chrony是一款备受推崇的工具&#xff0c;为Linux系统提供了更准确、更稳定的时间同步功能。本文将介绍Chrony的工作原理、优点…

亚信面试题

文章目录 2.Java基本数据类型?3.对象三大特征?4.多态和封装的含义及作用?5.方法重写和方法重载的区别?6.String/StringBuffer和StringBuilder区别?7.String常用方法有哪些?8.==和equals有什么区别?9.两个对象hashCode相同equals为true吗?10.ArrayList和LinkedList有什么…

WordPress网站迁移实战经验

前几日,网站服务器到期,换了服务商,就把我的WordPress的网站迁移到本地电脑了。方便以后文章迁移。 本次迁移网站主要经历以下几个步骤。 1.域名转出。 2.备份数据库及网站文件下载。 3.重新搭建WordPress网站。 4.网站文件及数据库导入。 下面详细介绍下每个步骤的操作…

Linux 安全 - 扩展属性xattr

文章目录 前言一、简介二、扩展属性命名空间2.1 简介2.2 security扩展属性2.3 System扩展属性2.4 Trusted扩展属性2.5 User扩展属性 三、用户空间使用3.1 setfattr/getfattr3.2 setxattr/getxattr/listxattr 参考资料 前言 一、简介 xattr - Extended attributes扩展属性是与…

【狂神说Java】redis

✅作者简介&#xff1a;CSDN内容合伙人、信息安全专业在校大学生&#x1f3c6; &#x1f525;系列专栏 &#xff1a;【狂神说Java】 &#x1f4c3;新人博主 &#xff1a;欢迎点赞收藏关注&#xff0c;会回访&#xff01; &#x1f4ac;舞台再大&#xff0c;你不上台&#xff0c…

【done】剑指 Offer 53 - II:0~n-1中缺失的数字

力扣&#xff0c;https://leetcode.cn/problems/que-shi-de-shu-zi-lcof/description/ solution1 线性扫描&#xff0c;一般情况 class Solution {public int takeAttendance(int[] records) {boolean[] visited new boolean[records.length 1];Arrays.fill(visited, fals…

解压过大文件(超过4GB)传输至服务器的问题

不能在终端执行unzip指令了。 1、通过终端 7za x 文件名.zip 2、通过jupyter notebook代码来解决 import zipfilef zipfile.ZipFile("dataset.zip",r) # 压缩文件在jupyter中的位置 for file in f.namelist():f.extract(file,"./dataset") …

docker部署gitlab 12.10.6过程

docker部署gitlab 12.10.6过程 1.docker安装 docker指定版本安装【官方文档步骤】 官方文档地址&#xff1a;https://docs.docker.com/engine/install/centos/ # 1.安装yum工具及设置docker-ce镜像库 sudo yum install -y yum-utils# 国外的镜像下载太慢了改成阿里云镜像库 s…

pipeline传参给job

场景&#xff1a;pipeline实现自动部署&#xff0c;job实现自动测试&#xff0c;但是只有部署dddd环境时&#xff0c;才调自动测试的job&#xff0c;所以需要在调自动测试job时&#xff0c;把参数传给测试job 上一个任务会显示下一步调谁 ------------------------------------…

解决:ERR This instance has cluster support disabled

问题描述 在使用Redisson做分布式锁&#xff0c;连接redis时&#xff0c;提示以下错误&#xff1a; 问题定位 通过指令&#xff1a; cluster nodes查看&#xff0c;发现 出现这种提示的原因&#xff0c;是因为此Redis实例已经禁用了集群(默认状态下是禁用状态)。 解决 …