Spring Boot解决循环注入问题
Spring Boot解决循环依赖注入问题
- 代码问题回显
- 启动错误日志
- 解决方案:使用事件驱动或通过 ApplicationContext 手动获取 Bean
- 1. 事件驱动设计
- 2. 使用 `ApplicationContext` 手动获取 Bean
- 3. 拆分逻辑
- 总结
代码问题回显
现有代码1 在InterestService中依赖MemberInterestService:
@Service
@AllArgsConstructor
public class InterestService {// 注意此处循环依赖注入private final MemberInterestService memberInterestService;private final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(2);/*** 调度下一个利息任务*/public void scheduleNextInterestTask() {// 省略其他代码...}
}
现有代码2 在MemberInterestService实现类中注入InterestService:
@Service
@AllArgsConstructor
public class MemberInterestServiceImpl extends ServiceImpl<MemberInterestMapper, MemberInterest> implements MemberInterestService {// 注意此处循环依赖注入private final InterestService interestService;@Overridepublic Boolean updateExpireStatus(MemberInterestExpireStatus body) {// 省略其他代码...if (updateById(interest)){// TODO 此处出现循环依赖注入(直接报错)interestService.scheduleNextInterestTask();return true;}}
}
启动错误日志
Description:
The dependencies of some of the beans in the application context form a cycle:
mobileLoginController (field private com.sinbyte.framework.web.service.SysLoginService
com.sinbyte.web.controller.system.MobileLoginController.loginService)
↓
sysLoginService (field private com.sinbyte.ray.service.MemberUserService
com.sinbyte.framework.web.service.SysLoginService.memberUserService)
┌─────┐
| memberInterestServiceImpl defined in file [D:\Java\IdeaProjects\alliance-server\alliance-ray\target\classes\com\sinbyte\ray\service\impl\MemberInterestServiceImpl.class]
↑ ↓
| interestService defined in file [D:\Java\IdeaProjects\alliance-server\alliance-ray\target\classes\com\sinbyte\ray\delay\InterestService.class]
└─────┘
在场景中, MemberInterestServiceImpl 需要调用 InterestService 的 scheduleNextInterestTask() 方法,但由于这两个服务之间存在循环依赖,直接注入会导致 Spring 启动时发生循环依赖错误。
解决方案:使用事件驱动或通过 ApplicationContext 手动获取 Bean
以下是一些可以解决循环依赖问题的方法:
1. 事件驱动设计
可以使用 Spring 的事件机制,将调用 scheduleNextInterestTask 的操作转变为事件驱动。具体做法是,当 MemberInterestServiceImpl 需要调用 scheduleNextInterestTask 时,发布一个自定义事件,InterestService 监听这个事件并执行相应的任务。
首先,定义一个自定义事件类:
import org.springframework.context.ApplicationEvent;
/*** 自定义事件驱动* @CreateDate: 2024/8/14 15:30*/
public class InterestTaskEvent extends ApplicationEvent {public InterestTaskEvent(Object source) {super(source);}
}
接着,在 MemberInterestServiceImpl 中发布事件,实现ApplicationEventPublisherAware并重写setApplicationEventPublisher方法:
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.ApplicationEventPublisherAware;
import org.springframework.stereotype.Service;@Service
@AllArgsConstructor
public class MemberInterestServiceImpl extends ServiceImpl<MemberInterestMapper, MemberInterest> implements MemberInterestService, ApplicationEventPublisherAware {// 事件发布器private ApplicationEventPublisher eventPublisher;@Overridepublic void setApplicationEventPublisher(@NotNull ApplicationEventPublisher applicationEventPublisher) {// 注入事件发布器this.eventPublisher = applicationEventPublisher;}@Overridepublic Boolean updateExpireStatus(MemberInterestExpireStatus body) {// 省略其他代码...if (updateById(interest)) {// 省略其他代码...eventPublisher.publishEvent(new InterestTaskEvent(this)); // 发布事件return true;}}
}
在 InterestService 中监听这个事件:
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Service;@Service
@AllArgsConstructor
public class InterestService {// 其他依赖...@EventListenerpublic void onInterestTaskEvent(InterestTaskEvent event) {scheduleNextInterestTask();}public void scheduleNextInterestTask() {// 省略其他代码...}
}
2. 使用 ApplicationContext 手动获取 Bean
如果你不希望使用事件驱动,还可以通过 Spring 的 ApplicationContext 手动获取 InterestService Bean,从而避免循环依赖。
在 MemberInterestServiceImpl 中引入 ApplicationContext 并在需要调用时获取 InterestService:
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Service;@Service
@Slf4j
@AllArgsConstructor
public class MemberInterestServiceImpl extends ServiceImpl<MemberInterestMapper, MemberInterest> implements MemberInterestService, ApplicationContextAware {private ApplicationContext applicationContext;private final RedisCache redisCache;private final PublicService publicService;private final MemberApplyBusinessService memberApplyBusinessService;private final MemberTransactionRecordService memberTransactionRecordService;private final MemberInterestPointService memberInterestPointService;@Overridepublic void setApplicationContext(ApplicationContext applicationContext) {this.applicationContext = applicationContext;}@Overridepublic Boolean updateExpireStatus(MemberInterestExpireStatus body) {// 省略其他代码...if (updateById(interest)) {// 省略其他代码...InterestService interestService = applicationContext.getBean(InterestService.class);interestService.scheduleNextInterestTask(); // 手动获取 Bean 并调用方法return true;}throw new ServiceException("更新失败");}
}
3. 拆分逻辑
如果可能,考虑将 InterestService 的部分逻辑拆分到一个新的服务中,以减少 InterestService 和 MemberInterestServiceImpl 之间的依赖关系。这可能需要对业务逻辑进行一定的重构,但从长期维护的角度来看,是一种更优雅的解决方案。
总结
通过以上方法,可以有效地解决循环依赖问题并在 MemberInterestServiceImpl 中安全地调用 InterestService 的方法。推荐使用事件驱动的方法,这不仅解决了循环依赖问题,还能让你的代码更具扩展性和松耦合。
生活不能过度的平坦,这样的生活才最有意义!
相关文章:
Spring Boot解决循环注入问题
Spring Boot解决循环依赖注入问题 代码问题回显启动错误日志解决方案:使用事件驱动或通过 ApplicationContext 手动获取 Bean1. 事件驱动设计2. 使用 ApplicationContext 手动获取 Bean3. 拆分逻辑 总结 代码问题回显 现有代码1 在InterestService中依赖MemberInte…...
《数据挖掘》期末考核重点
1.数据预处理的目的与形式 数据预处理的目的是提供干净,简洁,准确的数据,以达到简化模型和提高算法泛化能力的目的,使挖掘过程更有效,更容易,提高挖掘效率和准确性。 2.数据预处理的形式 数据清理&#…...
Golang | Leetcode Golang题解之第334题递增的三元子序列
题目: 题解: func increasingTriplet(nums []int) bool {n : len(nums)if n < 3 {return false}first, second : nums[0], math.MaxInt32for i : 1; i < n; i {num : nums[i]if num > second {return true} else if num > first {second n…...
HarmonyOs编写一个案例实现一个照片选择(阶段进阶 四种需求 逐一完善)
需求1. .实现照片选择 并将选择好的照片展示出来 import { GoodItem } from ../06/modules;Entry Component struct PhotoPage {State message: string 实现一个相册;State List: GoodItem[] [{goods_name: dsfjlsjkfsf,goods_price: 100,goods_img: https://img1.baidu.com…...
洗衣机洗衣服一些知识
01智能:按衣物多少自动调节合适水位的标准洗涤程序 (需要30分钟时间) 02:大物:较大,较厚的衣服洗涤 03:轻柔:毛织品或内衣洗涤 04:快速:少量清污衣服洗涤 (13分钟) 05:浸泡:先浸泡一段时间再洗涤 06:单洗:只洗衣不脱水 07:单脱:只脱水不洗衣 08:洁桶:清洁洗衣桶 准备工作: (1)…...
探索文件系统:高效、可靠的文件管理与访问机制
文件系统的功能规划 内存就像是一个书包,容量有限,只能带着一部分东西。而图书馆则是一个专门存储和管理文件的地方,拥有更大的容量,并且可以永久保存文件。为了能够快速找到需要的文件,我们需要有一个书单来记录每本…...
启程与远征Ⅸ--优化生成式人工智能以满足业务需求的框架
生成类似人类的文本和语音曾经只存在于科幻小说中。但 GPT-3 和 PaLM 等大型语言模型 (LLM) 的快速发展让这一愿景更接近现实,解锁了从聊天机器人到内容创作等一系列有前景的商业应用。 然而,通用基础模型往往无法满足行业用例的需求。企业对其生成式 A…...
canal数据同步工具介绍与应用
canal服务 canal介绍canal版本与环境canal 服务集canal应用场景: canal常见问题xml配置问题连接认证问题jar版本问题连接问题 canal介绍 1、Canal是阿里巴巴开源的MySQL增量数据订阅和消费工具,通过模拟MySQL的slave与master交互,捕…...
ubuntu18.04 设置静态地址
修改配置文件 sudo vim /etc/netplan/01-network-manager-all.yaml 代码如下: network: version: 2 renderer: NetworkManager ethernets: ens33: # 配置的网卡名称,可以使用ifconfig -a查看本机的网卡 dhcp4: no # 关闭动态IP设置 …...
jira敏捷开发管理工具视频教程Confluence工作流协同开发(2024)
正文: 随着Jira敏捷开发方法论的普及,Jira已经成为全球软件开发团队管理项目、任务和问题的首选工具。为了帮助团队更好地掌握Jira的核心功能,精心准备了一套全面开发技术及案例视频教程——《Jira敏捷开发管理工具视频教程Confluenc…...
【网络】TCP回显服务器和客户端的构造,以及相关bug解决方法
文章目录 ServerSocket构造方法方法 Socket构造方法方法 回显服务器(Echo Server)1. 构造方法2. 建立连接processConnection 方法的创建1. 读取请求并解析2. 根据请求计算响应3. 把响应写回给客户端 3. 完整代码 客户端(Echo Clientÿ…...
Python知识点:如何使用Boto3进行AWS服务管理
使用 boto3 来管理 AWS 服务是一个非常强大的方式,因为 boto3 是 AWS 提供的官方 Python SDK。下面是使用 boto3 管理 AWS 服务的基本步骤,包括设置、操作和常见的 AWS 服务示例。 1. 安装 boto3 首先,确保你已经安装了 boto3。可以使用 pi…...
Java - 正则表达式
Java 提供了 java.util.regex 包,它包含了 Pattern 和 Matcher 类,用于处理正则表达式的匹配操作。 正则表达式的模式 正则表达式的模式可以包括以下内容: 字面值字符:例如字母、数字、空格等,可以直接匹配它们自身。…...
Vue一款流行的JavaScript前端框架
1.Vue简介 Vue是一款用于构建用户界面的 JavaScript 框架。它基于标准 HTML、CSS 和 JavaScript 构建,并提供了一套声明式的、组件化的编程模型,帮助你高效地开发用户界面。无论是简单还是复杂的界面,Vue 都可以胜任。 Vue所关注的核心是MVC…...
GPT-SoVITS
文章目录 model archS1 ModelS2 model model arch S1 model: AR model–ssl tokensS2 model: VITS,ssl 已经是mel 长度线性相关,MRTE(ssl_codes_embs, text, global_mel_emb)模块,将文本加强相关,学到一个参考结果 S1 Model cla…...
linux高级编程——文件IO(常用函数大全)
1.相关介绍及常用函数 Linux高级编程中的目录IO操作是文件系统编程的一个重要组成部分,主要涉及到目录的打开、读取、遍历和关闭等操作。以下是一些基本的目录IO操作和相关的系统调用函数 1.1 opendir函数 打开目录:使用opendir函数打开一个目录&#…...
matplotlib画图
Matplotlib 先写一个最简单的: import matplotlib.pyplot as plt plt.plot([1,4],[2,8]) #plot画折线图plt.show() 确定两个点画一条线 import matplotlib.pyplot as plt x[1,23,4,56,7,6] #x轴数据 y[22,44,56,67,43,2] #y轴数据 s[22,43,33,44,43,7] plt.p…...
Jetpack 各种框架简介
Jetpack是Google推出的一套为Android开发提供极大便利的组件、工具和指导集,旨在帮助开发者快速构建高质量的应用,并遵循最佳实践。 Jetpack不仅是一个提高开发效率的工具集,还是Android开发的未来方向。它通过整合各种组件和工具࿰…...
海康VisionMaster使用学习笔记5-开机自启动
开机自启动 在实际应用中,用户会希望机台上电开机后,软件能自启动避免现场人员误操作,减少机台重新上电时的操作步骤以提升效率。 设置 打开VM,点击设置,软件设置->开机自启动->勾选开机自启动->确定 默认运行界面 启动时以设定的…...
驾驭数据之序:SQL序列的奥秘与实现
标题:驾驭数据之序:SQL序列的奥秘与实现 摘要 在数据库管理中,保证数据的有序性和唯一性是至关重要的。SQL序列(Sequence)作为一种强大的数据库对象,为我们提供了一种在不同数据库系统中生成连续数字的手…...
避开这3个坑!uni-app直传腾讯云COS的实战避坑指南
uni-app直传腾讯云COS的三大高频问题与增强方案 1. 临时密钥失效的实战解决方案 临时密钥失效是开发者最常遇到的痛点之一。想象一下这样的场景:用户正在上传重要文件,突然提示"密钥已过期",这种体验有多糟糕?我们先来…...
Bunker_mini_dev实战:多雷达(AVIA MID360)ROS1驱动融合与rviz点云同屏可视化
1. 多雷达ROS1驱动融合实战背景 最近在Bunker_mini_dev机器人开发平台上折腾多激光雷达融合,发现不少开发者对Livox AVIA和MID360这两款雷达的ROS1驱动配置存在困惑。我自己踩过不少坑,今天就把从驱动安装到rviz同屏显示的全流程梳理一遍。这种配置在自动…...
Token 中文定名词元,国产 AI 工具如何抢占词元红利?
3 月 23 日,中国发展高层论坛 2026 年年会上,国家数据局局长刘烈宏正式官宣:AI 领域核心术语 Token 的中文标准译名确定为“词元”。这一官方定名,结束了之前 “令牌”“代币”“词块” 等译法混用的行业乱象,为中国 A…...
移动热源坐标参数
comsol激光熔覆仿真模型,热流耦合,包含马兰戈尼非等温模激光熔覆工艺仿真里有个特有意思的物理现象——熔池表面会出现类似水波纹的流动轨迹。这可不是普通的热胀冷缩,而是马兰戈尼效应在金属熔液里跳"物理芭蕾"。咱们今天就用COMS…...
深度解析Scratch-www:模块化架构如何支撑全球最大编程教育平台
深度解析Scratch-www:模块化架构如何支撑全球最大编程教育平台 【免费下载链接】scratch-www Standalone web client for Scratch 项目地址: https://gitcode.com/gh_mirrors/scr/scratch-www Scratch-www作为全球最大的少儿编程教育平台Scratch的独立Web客户…...
Janus-Pro-7B案例展示:同一张设计稿→品牌调性分析→竞品风格迁移生成
Janus-Pro-7B案例展示:同一张设计稿→品牌调性分析→竞品风格迁移生成 Janus-Pro-7B 是一个统一的多模态理解与生成AI模型,能够同时处理图像理解和文生图生成任务。本文将展示如何利用这个强大的模型,从一张设计稿出发,完成品牌调…...
FPGA图像处理入门:OV7670+DVP接口数据采集的那些‘坑’与优化策略
FPGA图像处理实战:OV7670DVP接口数据采集的工程级优化指南 当你在实验室调试OV7670摄像头时,是否遇到过这些场景:VGA显示器上的图像突然撕裂、颜色通道错乱,或是帧率莫名其妙降到个位数?作为一款经典的VGA分辨率CMOS传…...
图像标注难题如何破解?LabelImg工具全面解析与实战指南
图像标注难题如何破解?LabelImg工具全面解析与实战指南 【免费下载链接】labelImg LabelImg is now part of the Label Studio community. The popular image annotation tool created by Tzutalin is no longer actively being developed, but you can check out L…...
Go HTTP Server 性能分析与优化
Go HTTP Server 性能分析与优化 在当今高并发的互联网应用中,HTTP Server的性能直接决定了用户体验和系统稳定性。Go语言凭借其轻量级协程和高效的网络库,成为构建高性能HTTP服务的首选之一。即使使用Go,开发者仍需深入分析性能瓶颈并进行针…...
300FPS的实时目标跟踪是怎么炼成的?手把手拆解KCF算法里的数学魔法
300FPS实时目标跟踪背后的数学魔法:KCF算法深度解密 在计算机视觉领域,实时目标跟踪一直是个令人着迷又充满挑战的问题。想象一下,当你在观看一场足球比赛时,摄像机需要实时锁定某个球员;或者当自动驾驶汽车行驶时&am…...
