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

Spring循环依赖报错别头疼,除了@Lazy,还有这些组合拳打法(附场景代码)

Spring循环依赖实战指南超越Lazy的七种解决方案遇到Spring容器启动时抛出BeanCurrentlyInCreationException异常是许多Java开发者成长路上的必经之痛。特别是在微服务架构中随着业务模块不断拆分和重组服务层之间的循环依赖几乎成为架构设计中的常态挑战。本文将带你深入理解Spring处理循环依赖的底层机制并为你提供一套完整的解决方案工具箱。1. 循环依赖的本质与Spring的三级缓存要真正解决循环依赖问题首先需要理解Spring容器管理Bean生命周期的核心机制。Spring通过三级缓存来优雅地处理大多数循环依赖场景// 简化版的三级缓存结构示意 public class DefaultSingletonBeanRegistry { private final MapString, Object singletonObjects new ConcurrentHashMap(256); // 一级缓存完整Bean private final MapString, Object earlySingletonObjects new ConcurrentHashMap(16); // 二级缓存早期引用 private final MapString, ObjectFactory? singletonFactories new HashMap(16); // 三级缓存对象工厂 }工作流程解析当创建Bean A时首先将A的原始对象工厂放入三级缓存在填充A的属性时发现需要Bean B开始创建B创建B时同样需要A此时从三级缓存获取A的早期引用B创建完成后A得以继续初始化最终移入一级缓存这种机制完美解决了属性注入场景下的循环依赖但遇到构造器注入时就会失效。因为构造器注入需要在实例化阶段就获得依赖对象而此时Bean甚至还没有被创建出来。提示Spring 5.2之后对构造器注入的循环依赖检测更加严格会提前抛出异常而不是等到堆栈溢出2. Lazy注解的深度应用场景虽然Lazy常被当作解决循环依赖的银弹但它的实际作用远不止于此。理解其工作原理才能正确使用Service public class OrderService { private final UserService userService; Autowired public OrderService(Lazy UserService userService) { this.userService userService; } }Lazy的核心价值创建代理对象延迟实际初始化打破初始化顺序的强依赖特别适合解决构造器注入的循环依赖典型使用场景对比场景类型适用性潜在风险跨模块服务调用★★★★★可能掩盖设计问题基础组件初始化★★★★☆启动顺序不可控测试环境配置★★★☆☆可能影响测试稳定性值得注意的是滥用Lazy可能导致启动时异常延迟到运行时才发现调试困难代理对象掩盖了真实调用栈性能损耗额外的代理调用开销3. 架构层面的六种解决方案3.1 接口抽象与中间层这是最符合设计原则的解决方案。通过引入接口或中间服务层将直接依赖转换为间接依赖public interface IUserValidator { boolean validate(User user); } Service public class OrderService { Autowired private IUserValidator userValidator; } Service public class UserService implements IUserValidator { // 实现验证逻辑 }优势完全消除循环依赖符合开闭原则接口契约明确3.2 事件驱动模型使用Spring事件机制实现解耦Service public class OrderService { Autowired private ApplicationEventPublisher eventPublisher; public void createOrder(Order order) { eventPublisher.publishEvent(new OrderCreatedEvent(this, order)); } } Service public class UserService { EventListener public void handleOrderCreated(OrderCreatedEvent event) { // 处理订单创建逻辑 } }3.3 方法注入替代字段注入Spring提供了独特的方法注入方式Service public class OrderService { public void processOrder() { UserService userService obtainUserService(); // 使用userService } Lookup protected UserService obtainUserService() { return null; // 实际由Spring实现 } }3.4 配置类集中管理将相互依赖的Bean统一在配置类中声明Configuration public class ServiceConfig { Bean public OrderService orderService() { return new OrderService(userService()); } Bean public UserService userService() { return new UserService(orderService()); } }3.5 ApplicationContextAware方案让Bean主动获取依赖Service public class OrderService implements ApplicationContextAware { private ApplicationContext context; public void setApplicationContext(ApplicationContext context) { this.context context; } private UserService getUserService() { return context.getBean(UserService.class); } }3.6 构造器注入Lazy组合Spring 4.3的优化方案Service public class OrderService { private final UserService userService; public OrderService(Lazy UserService userService) { this.userService userService; } }4. 决策树如何选择最佳方案面对循环依赖问题时建议按照以下流程评估是否必须循环依赖是 → 进入步骤2否 → 重构设计依赖类型是什么构造器注入 → 考虑Lazy或方法注入Setter/字段注入 → 三级缓存通常能处理性能要求如何高 → 避免Lazy代理开销一般 → Lazy可接受架构演进方向长期维护 → 优先接口解耦短期方案 → 选择最简实现方案对比表解决方案实现难度侵入性性能影响可维护性接口抽象中低无★★★★★事件驱动高中轻微★★★★☆Lazy注解低中中等★★☆☆☆方法注入中高轻微★★★☆☆配置类管理中中无★★★☆☆5. 实战案例电商系统中的订单-用户循环假设我们有一个电商系统订单服务需要用户服务验证用户状态而用户服务又需要订单服务计算用户活跃度// 初始问题代码 Service public class OrderService { Autowired private UserService userService; public void createOrder(Order order) { if(!userService.isActive(order.getUserId())) { throw new IllegalStateException(User inactive); } // 创建订单逻辑 } } Service public class UserService { Autowired private OrderService orderService; public boolean isActive(Long userId) { int orderCount orderService.getRecentOrderCount(userId); return orderCount 0; } }重构方案选择引入UserActivityService作为中间层将活跃度计算改为事件驱动使用缓存减少实时依赖最终实现public interface UserActivityEvaluator { boolean isActive(Long userId); } Service public class OrderService { Autowired private UserActivityEvaluator activityEvaluator; public void createOrder(Order order) { if(!activityEvaluator.isActive(order.getUserId())) { throw new IllegalStateException(User inactive); } // 创建订单逻辑 } } Service public class UserService implements UserActivityEvaluator { Autowired private OrderRepository orderRepository; Override public boolean isActive(Long userId) { return orderRepository.countRecentOrders(userId) 0; } }6. 测试策略与陷阱规避循环依赖场景下的测试需要特别注意单元测试技巧public class OrderServiceTest { private OrderService orderService; private UserService userServiceMock; BeforeEach void setUp() { userServiceMock Mockito.mock(UserService.class); orderService new OrderService(userServiceMock); } Test void shouldRejectInactiveUser() { when(userServiceMock.isActive(any())).thenReturn(false); assertThrows(IllegalStateException.class, () - orderService.createOrder(new Order())); } }集成测试要点使用DirtiesContext确保上下文重置监控Bean初始化时间验证代理对象的正确行为常见陷阱混合使用构造器注入和字段注入Async方法与循环依赖结合使用AOP增强导致的代理嵌套问题7. Spring Boot中的特殊处理Spring Boot对循环依赖有额外的处理机制application.properties配置# 开启循环依赖严格模式默认值 spring.main.allow-circular-referencesfalse启动时检测SpringBootApplication public class MyApp { public static void main(String[] args) { new SpringApplicationBuilder(MyApp.class) .setAllowCircularReferences(true) .run(args); } }在Spring Boot 2.6版本中循环依赖的默认处理方式变得更加严格建议开发者尽早解决架构层面的循环依赖问题而不是依赖框架的容错机制。

相关文章:

Spring循环依赖报错别头疼,除了@Lazy,还有这些组合拳打法(附场景代码)

Spring循环依赖实战指南:超越Lazy的七种解决方案 遇到Spring容器启动时抛出BeanCurrentlyInCreationException异常,是许多Java开发者成长路上的必经之痛。特别是在微服务架构中,随着业务模块不断拆分和重组,服务层之间的循环依赖几…...

如何用LeaguePrank轻松自定义你的英雄联盟游戏展示?3分钟快速上手指南

如何用LeaguePrank轻松自定义你的英雄联盟游戏展示?3分钟快速上手指南 【免费下载链接】LeaguePrank 项目地址: https://gitcode.com/gh_mirrors/le/LeaguePrank 想要在英雄联盟中展示与众不同的游戏身份吗?厌倦了千篇一律的段位显示和头像&…...

3个核心功能解析:FakeLocation如何实现应用级位置模拟的精准控制

3个核心功能解析:FakeLocation如何实现应用级位置模拟的精准控制 【免费下载链接】FakeLocation Xposed module to mock locations per app. 项目地址: https://gitcode.com/gh_mirrors/fak/FakeLocation FakeLocation是一款基于Xposed框架的Android位置模拟…...

csp信奥赛C++高频考点专项训练之字符串 --【字符统计】:连续出现的字符

csp信奥赛C高频考点专项训练之字符串 --【字符统计】:连续出现的字符 题目描述 给定一个字符串,在字符串中寻找第一个连续出现次数不低于 kkk 次的字符。 输入格式 222 行。第 111 行是 kkk;第 222 行是仅包含大小写字母的字符串。 输出格…...

如何使用fastai Captum实现深度学习模型可解释性与特征重要性分析:完整指南

如何使用fastai Captum实现深度学习模型可解释性与特征重要性分析:完整指南 【免费下载链接】fastai The fastai deep learning library 项目地址: https://gitcode.com/gh_mirrors/fa/fastai fastai是一个强大的深度学习库,它通过Captum集成提供…...

csp信奥赛C++高频考点专项训练之字符串 --【字符统计】:「MYOI-R3」字符串

csp信奥赛C高频考点专项训练之字符串 --【字符统计】:「MYOI-R3」字符串 题目描述 给定字符串 s,ts,ts,t。 现在你要在 s,ts,ts,t 中删除一些字符并将它们重新排列使 ststst。 问操作后的 ∣s∣|s|∣s∣(即字符串 sss 的长度)最大是多少&a…...

实战演练:在快马平台用ai生成vivado uart通信项目,体验完整开发流程

今天想和大家分享一个特别实用的FPGA开发实战经验——如何在InsCode(快马)平台快速搭建一个完整的UART串口通信控制器项目。这个项目不仅包含了Verilog核心代码,还涉及约束文件、测试平台等工程必备要素,特别适合想学习FPGA开发或需要快速验证硬件算法的…...

GEPA实验跟踪与日志系统:如何有效监控和记录优化过程

GEPA实验跟踪与日志系统:如何有效监控和记录优化过程 【免费下载链接】gepa Optimize prompts, code, and more with AI-powered Reflective Text Evolution 项目地址: https://gitcode.com/gh_mirrors/ge/gepa GEPA(GitHub 加速计划)…...

告别混乱标注!用Labelme+Python脚本一键生成COCO格式实例分割数据集

告别混乱标注!用LabelmePython脚本一键生成COCO格式实例分割数据集 在计算机视觉领域,高质量的数据集是模型训练的基础。然而,许多研究者和开发者在创建自定义实例分割数据集时,常常陷入标注格式转换的泥潭。本文将介绍如何利用La…...

别再硬改代码了!Pycharm 2023.3 编辑配置里这个‘形参’功能,5分钟搞定命令行传参

别再硬改代码了!Pycharm 2023.3 编辑配置里这个‘形参’功能,5分钟搞定命令行传参 每次调试Python脚本时反复修改default值,或是临时注释requiredTrue的检查逻辑?这种"暴力调试法"不仅让版本管理变得混乱,更…...

从SMILES字符串到RDKit分子对象:一个关于手性保留的完整处理流程指南

从SMILES字符串到RDKit分子对象:手性保留的完整处理流程指南 在药物设计和计算化学领域,分子手性信息的准确传递常常决定着整个研究项目的成败。一个看似简单的SMILES字符串转换操作,可能在不经意间丢失关键立体化学信息,导致后续…...

i915-sriov-dkms高级配置技巧:自定义虚拟功能数量与资源分配

i915-sriov-dkms高级配置技巧:自定义虚拟功能数量与资源分配 【免费下载链接】i915-sriov-dkms dkms module of Linux i915 driver with SR-IOV support 项目地址: https://gitcode.com/gh_mirrors/i9/i915-sriov-dkms i915-sriov-dkms是一个为Linux i915驱动…...

告别手动截图:3分钟学会从视频中智能提取PPT内容

告别手动截图:3分钟学会从视频中智能提取PPT内容 【免费下载链接】extract-video-ppt extract the ppt in the video 项目地址: https://gitcode.com/gh_mirrors/ex/extract-video-ppt 你是否曾在观看在线课程或会议录像时,想要保存那些一闪而过的…...

3分钟快速指南:如何使用calibre-douban插件一键获取豆瓣图书元数据

3分钟快速指南:如何使用calibre-douban插件一键获取豆瓣图书元数据 【免费下载链接】calibre-douban Calibre new douban metadata source plugin. Douban no longer provides book APIs to the public, so it can only use web crawling to obtain data. This is a…...

如何快速构建专业CMS系统:Cookiecutter模板终极指南

如何快速构建专业CMS系统:Cookiecutter模板终极指南 【免费下载链接】cookiecutter A cross-platform command-line utility that creates projects from cookiecutters (project templates), e.g. Python package projects, C projects. 项目地址: https://gitco…...

Framer Manager:为AI Agent设计的自动化站点管理工具

1. 项目概述:Framer Manager,一个为AI Agent设计的自动化站点管理工具 如果你和我一样,日常运营着几个基于Framer搭建的网站,那么对Framer的编辑器界面一定又爱又恨。爱的是它的设计体验和灵活性,恨的是那些重复性的管…...

@prb/hardhat-template安全最佳实践:避免智能合约常见漏洞的10个方法

prb/hardhat-template安全最佳实践:避免智能合约常见漏洞的10个方法 【免费下载链接】hardhat-template Hardhat-based template for developing Solidity smart contracts 项目地址: https://gitcode.com/gh_mirrors/ha/hardhat-template 在区块链开发领域&…...

新手福音:用快马AI零基础生成你的第一个yw1168登录页面

作为一名刚接触网页开发的新手,最近尝试用InsCode(快马)平台制作了一个简单的yw1168登录页面。整个过程比我预想的顺利很多,特别适合像我这样零基础的小白快速上手。下面分享我的实践过程和学到的知识点: 页面基础结构搭建 登录页面的核心是H…...

终极React Native Elements安全审计指南:从漏洞检测到修复的完整路径

终极React Native Elements安全审计指南:从漏洞检测到修复的完整路径 【免费下载链接】react-native-elements Cross-Platform React Native UI Toolkit 项目地址: https://gitcode.com/gh_mirrors/re/react-native-elements React Native Elements作为跨平台…...

ComfyUI-Manager终极指南:5步快速解决节点安装失败问题

ComfyUI-Manager终极指南:5步快速解决节点安装失败问题 【免费下载链接】ComfyUI-Manager ComfyUI-Manager is an extension designed to enhance the usability of ComfyUI. It offers management functions to install, remove, disable, and enable various cust…...

逆向工程视角:深度解析百度网盘直链解析技术的演进与实践

逆向工程视角:深度解析百度网盘直链解析技术的演进与实践 【免费下载链接】baidu-wangpan-parse 获取百度网盘分享文件的下载地址 项目地址: https://gitcode.com/gh_mirrors/ba/baidu-wangpan-parse 你是否曾因百度网盘的下载速度限制而感到困扰&#xff1f…...

番茄小说下载器完整指南:5分钟打造个人离线数字图书馆

番茄小说下载器完整指南:5分钟打造个人离线数字图书馆 【免费下载链接】Tomato-Novel-Downloader 番茄小说下载器不精简版 项目地址: https://gitcode.com/gh_mirrors/to/Tomato-Novel-Downloader 番茄小说下载器是一款功能强大的开源Rust工具,专…...

PopClip扩展开发最佳实践:配置、图标设计到发布的全流程教程

PopClip扩展开发最佳实践:配置、图标设计到发布的全流程教程 【免费下载链接】PopClip-Extensions Source code for extensions in the official PopClip Extensions directory. 项目地址: https://gitcode.com/gh_mirrors/po/PopClip-Extensions PopClip扩展…...

Sparse-BitNet:1.58位量化与半结构化稀疏的模型压缩技术

1. 项目背景与核心价值在边缘计算设备爆炸式增长的今天,模型压缩技术正面临前所未有的挑战。传统量化方法往往在精度和效率之间难以平衡,而稀疏化方案又面临硬件兼容性问题。Sparse-BitNet的创新之处在于将极低位宽量化(1.58位)与…...

终极指南:如何将Electron-React-Boilerplate与Angular无缝整合,构建企业级跨平台应用

终极指南:如何将Electron-React-Boilerplate与Angular无缝整合,构建企业级跨平台应用 【免费下载链接】electron-react-boilerplate A Foundation for Scalable Cross-Platform Apps 项目地址: https://gitcode.com/gh_mirrors/el/electron-react-boil…...

如何高效使用番茄小说下载器:一站式跨平台解决方案指南

如何高效使用番茄小说下载器:一站式跨平台解决方案指南 【免费下载链接】Tomato-Novel-Downloader 番茄小说下载器不精简版 项目地址: https://gitcode.com/gh_mirrors/to/Tomato-Novel-Downloader 番茄小说下载器是一款基于Rust开发的高性能跨平台工具&…...

液晶LCD1602的测试

1.硬件电路图2.测试程序/************************************************* 文件描述 : LCD1602液晶屏显示字符串八位模式测试程序* 程序文件 : main.c * 版 本 : 1.0* 作 者 : 火龙电子工作室* 日 期 : 2017.01.01* 芯 片 …...

STC89c52RC的看门狗使用方法

核心:控制 WDT_CONTR 寄存器看门狗功能的全部控制都通过一个8位的特殊功能寄存器 WDT_CONTR 实现。定义寄存器地址:由于标准头文件 reg51.h 未包含其定义,使用前需手动声明,其地址为 0xE1sfr WDT_CONTR 0xE1;寄存器结构解析&…...

Qwen-VL多模态模型的空间推理优化与实践

1. 项目背景与核心价值Qwen-VL作为当前多模态领域的前沿模型,其训练过程与空间推理能力的结合一直是计算机视觉和自然语言处理交叉领域的研究热点。这个项目本质上是在探索视觉语言模型(Vision-Language Model)如何通过特定训练策略提升对三维空间关系的理解能力——…...

魔兽争霸3终极优化指南:如何免费解锁180帧流畅体验

魔兽争霸3终极优化指南:如何免费解锁180帧流畅体验 【免费下载链接】WarcraftHelper Warcraft III Helper , support 1.20e, 1.24e, 1.26a, 1.27a, 1.27b 项目地址: https://gitcode.com/gh_mirrors/wa/WarcraftHelper 还在为魔兽争霸3的卡顿和画面限制烦恼吗…...