深度剖析Spring循环依赖(实战Bug)

目录

  • 前言
  • 1. 问题所示
  • 2. 原理分析
  • 3. 基本知识
  • 4. @Lazy注解

前言

通过实战更好的回馈问题,意识更加深刻

起因是我出现如下问题之后,才意识到中了Spring的循环依赖了!

1. 问题所示

在执行项目的时候,出现如下问题,问题如下所示:

org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'tyreRepareOrderController' defined in file [F:\java_project\xx\xx-service\xx-equipment\target\classes\org\xx\equipment\controller\TyreRepareOrderController.class]: Unsatisfied dependency expressed through constructor parameter 0; nested exception is org.springframework.beans.factory.BeanCurrentlyInCreationException: Error creating bean with name 'tyreRepareOrderServiceImpl': Bean with name 'tyreRepareOrderServiceImpl' has been injected into other beans [tyreRepareOrderServiceImpl] in its raw version as part of a circular reference, but has eventually been wrapped. This means that said other beans do not use the final version of the bean. This is often the result of over-eager type matching - consider using 'getBeanNamesForType' with the 'allowEagerInit' flag turned off, for example.at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:769)at org.springframework.beans.factory.support.ConstructorResolver.autowireConstructor(ConstructorResolver.java:218)at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.autowireConstructor(AbstractAutowireCapableBeanFactory.java:1338)at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1185)

截图如下所示:

在这里插入图片描述

2. 原理分析

这是Spring循环依赖的经典问题了

原本我是ServiceImpl类中实现了Service中的方法!
之后又在ServiceImpl类 通过 注入 Service方法来操作,说的普通一点就是死锁了!

解决方案就是要么使用Spring中的三级缓存(这是面试的经典题)
或者使用this.super直接使用,从而不用再次注入,而又能调用其方法!

3. 基本知识

Spring循环依赖是指两个或多个Bean彼此依赖,形成一个循环引用的情况。这种情况可能导致应用程序无法正常启动或运行,因此需要特殊处理。

在Spring中,循环依赖的处理是通过使用三级缓存解决的。三级缓存是指Spring容器中的三个缓存区域,分别是singletonObjects、earlySingletonObjects和singletonFactories。在处理循环依赖时,Spring会通过提前暴露半成品Bean的方式来解决。

具体来说,当一个Bean被创建时,Spring会将其提前暴露给singletonFactories缓存,即使它还没有完全初始化。这样,其他Bean在需要引用这个Bean时,可以通过singletonFactories获取到它的引用,而不是等待其完全初始化。当Bean初始化完成后,会将其放入singletonObjects缓存,表示完全初始化的Bean。

这样,循环依赖中的Bean就能够在初始化过程中相互引用,而不会导致死循环或空指针异常。

需要注意的是,Spring的循环依赖处理机制对于单例(singleton)的Bean是有效的,对于其他作用域的Bean(如prototype)可能会有不同的处理方式。

下面是一个简单的Java代码示例,演示了Spring中的循环依赖情况:

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;@Component
public class A {@Autowiredprivate B b;// Other code...
}@Component
public class B {@Autowiredprivate A a;// Other code...
}

在上述例子中,类A依赖类B,而类B又依赖类A,形成了循环依赖。

Spring会通过三级缓存解决这种循环依赖。当一个Bean被创建时,它会被提前暴露给singletonFactories缓存,以便其他Bean可以引用它。下面是如何解除循环依赖的代码解释:

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Component;@Component
public class A {@Autowired@Lazyprivate B b;// Other code...
}@Component
public class B {@Autowired@Lazyprivate A a;// Other code...
}

在解除循环依赖时,可以使用@Lazy注解标记依赖关系,表示在需要时才进行实际的Bean初始化。

这样,当Bean A和Bean B相互引用时,它们的初始化将被延迟到第一次实际使用时。这有助于打破循环依赖,因为Bean的初始化被推迟到真正需要的时候。

4. @Lazy注解

@Lazy注解是Spring框架提供的一种机制,用于延迟加载(Lazy Initialization)Bean。

当一个Bean被标记为@Lazy时,它的初始化将会被推迟到第一次被实际使用的时候,而不是在容器启动时立即初始化。

延迟加载的一些补充:

优点作用范围使用场景
1.性能优化: 避免在应用启动时就初始化所有Bean,节省了启动时间和资源。

2.解决循环依赖: 通过延迟加载,可以解决某些情况下的循环依赖问题,如前面提到的循环依赖的处理。
@Lazy注解可以用于标记在字段、方法、构造函数或配置类(@Configuration)的@Bean方法上。适用于那些在启动时不一定会被立即使用的Bean,特别是当Bean的初始化过程较为耗时或涉及到一些外部资源。

与单例(Singleton)的关系: 默认情况下,Spring容器中的Bean是单例的。
使用@Lazy注解可以将单例Bean的初始化延迟到第一次使用时。

XML配置中的等效方式: 在XML配置中,可以使用lazy-init="true"属性来实现与@Lazy注解相同的效果。

<bean id="myBean" class="com.example.MyBean" lazy-init="true"><!-- Bean configuration -->
</bean>

总体而言,@Lazy注解是Spring框架提供的一个有用的特性,可用于优化应用程序的启动性能,尤其是在处理大型应用或有复杂依赖关系的情况下。

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

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

相关文章

2024.1.19 寒假训练记录(2)

昨晚的cf打得非常抽象&#xff0c;成功从蓝掉到青&#xff0c;不过在心理预期范围内&#xff0c;可以接受&#xff0c;之后每一场都会跟着打大号&#xff0c;能力的提升比表面上的分数更加重要 文章目录 CF 1922A Tricky TemplateCF 1922B Forming TrianglesCF 1922C Closest …

面试之Glide如何绑定Activity的生命周期

Glide绑定Activity生命周期 Glide.with() 下面都是它的重载方法&#xff0c;Context&#xff0c;Activity&#xff0c;FragmentActivity, Fragment, android.app.Fragment fragment,View都可以作为他的参数&#xff0c;内容大同小异&#xff0c;都是先getRetriever&#xff0…

2649. 嵌套数组生成器

说在前面 &#x1f388;不知道大家对于算法的学习是一个怎样的心态呢&#xff1f;为了面试还是因为兴趣&#xff1f;不管是出于什么原因&#xff0c;算法学习需要持续保持。 题目描述 现给定一个整数的 多维数组 &#xff0c;请你返回一个生成器对象&#xff0c;按照 中序遍历…

01 软件工程项目开发流程-需求调研

一、需求调研 获取到客户项目需求后&#xff0c;首先进行项目需求调研&#xff0c;调研项目的业务需求、用户需求、系统需求、性能需求、非功能需求、约束和限制、需求优先级等&#xff0c;具体如下&#xff1a; 业务需求&#xff1a;了解客户的业务目标和战略&#xff0c;这是…

016-Vue-黑马2023:前后端分离开发(在线接口文档),前端工程化、Element、vue编写一个完成页面、Vue路由、vue打包部署到nginx

第三节 前后端分离开发 1、介绍 开发模式 前后端混合开发&#xff1a;传统开发模式 前后端分离开发&#xff1a;当前最为主流的开发模式 页面原型需求案例&#xff1a;分析出接口文档 离线开发文档示例&#xff1a; 2、YAPI&#xff08;官网已停用&#xff09; 202…

汽车微电机行业研究:预计2029年将达到188亿美元

微电机行业是技术密集型行业&#xff0c;其起源于欧洲的德国、瑞士等国家&#xff0c;发展于日本。随着改革开放&#xff0c;中国作为发展中国家&#xff0c;承接了德国、日本等发达国家的汽车微电机产业转移&#xff0c;技术扩散逐步向我国转移。 微特电机广泛应用于信息处理设…

优化微信小程序更新体验:异步更新与强制更新方案解析

在微信小程序的开发和迭代过程中&#xff0c;新版本覆盖率的问题一直备受关注。由于小程序采用异步更新机制&#xff0c;在用户首次打开或冷启动时才会检查并下载新版本&#xff0c;导致部分用户无法及时应用上最新版本。为了解决这一问题&#xff0c;微信团队经过深入研究和讨…

【JavaScript】面向对象之多态

重学JavaScript07----- 面向对象之多态 文章目录 重学JavaScript07----- 面向对象之多态多态 多态 面向对象的三大特性&#xff1a;封装、继承、多态。 JavaScript有多态吗&#xff1f; 维基百科对多态的定义&#xff1a;多态&#xff08;英语&#xff1a;polymorphism&#…

QML与C++交互详解

文章目录 介绍一. QML中创建C对象二. QML与C的交互结论 介绍 在现代软件开发中&#xff0c;图形用户界面&#xff08;GUI&#xff09;是用户与程序交互的重要组成部分。Qt框架提供了一种强大的方式来构建跨平台的GUI应用程序&#xff0c;其中QML&#xff08;Qt Meta-Object La…

C语言中的递归过程和递归工作栈

递归过程和关联的递归工作堆栈的示例&#xff1a; c #include <stdio.h> int factorial(int n) { if (n 0) return 1; else return n * factorial(n - 1); } int main() { int result factorial(5); printf("Factorial: %d\n", result); return 0; } 在这…

vue解决部署文件缓存方式

问题&#xff1a;系统上线后&#xff0c;除了bug。紧急修复后&#xff0c;发现安卓正常&#xff0c;ios上海市有问题。通过debug后发现&#xff0c;ios上缓存严重。于是想到了打包文件加时间戳的方式来去除缓存。 vue2 配置打包输出文件名方式&#xff1a; const baseUrl &qu…

【Java 设计模式】结构型之组合模式

文章目录 1. 定义2. 应用场景3. 代码实现结语 组合模式&#xff08;Composite Pattern&#xff09;是一种结构型设计模式&#xff0c;它允许将对象组合成树形结构以表示“部分-整体”的层次结构。组合模式使得客户端可以统一处理单个对象和对象组合&#xff0c;无需区分它们之间…

设计社交网络的数据结构

1: 确定 Use Case 和 约束 Use Cases User 搜索某人然后看到被搜索人的最短路径Service 有高可用 约束和假设 状态假设 Traffic 不是平均分布的 一些被搜索者是更加受欢迎的&#xff0c;某些被搜索者只会被搜索一次图数据不适用与单个机器图的分布是轻量级的一亿个 User每…

canvas绘制N角形,锯齿状

查看专栏目录 canvas实例应用100专栏&#xff0c;提供canvas的基础知识&#xff0c;高级动画&#xff0c;相关应用扩展等信息。canvas作为html的一部分&#xff0c;是图像图标地图可视化的一个重要的基础&#xff0c;学好了canvas&#xff0c;在其他的一些应用上将会起到非常重…

C++入门【31-C++ 基本的输入输出】

C 标准库提供了一组丰富的输入/输出功能&#xff0c;我们将在后续的章节进行介绍。本章将讨论 C 编程中最基本和最常见的 I/O 操作。 C 的 I/O 发生在流中&#xff0c;流是字节序列。如果字节流是从设备&#xff08;如键盘、磁盘驱动器、网络连接等&#xff09;流向内存&#…

【Python 千题 —— 基础篇】姓名与性别

题目描述 题目描述 姓名与学号。班级中有 Tom、Alan、Bob、Candy、Sandy 五个人,他们的性别分别是男、男、男、女、女;请将他们的姓名与性别关联成字典,转换成字符串并输出。 输入描述 无 输出描述 输出字典转换成的字符串。 示例 示例 ① 输出: {Tom: 男, Alan:…

在线扒站网PHP源码-在线扒站工具网站源码

源码介绍 这是一款在线的网站模板下载程序&#xff0c;也就是我们常说的扒站工具&#xff0c;利用它我们可以很轻松的将别人的网站模板样式下载下来&#xff0c;这样就可以大大提高我们编写前端的速度了&#xff01;注&#xff1a;扒取的任何站点不得用于商业、违法用途&#…

kafka参数配置参考和优化建议 —— 筑梦之路

对于Kafka的优化&#xff0c;可以从以下几个方面进行思考和优化&#xff1a; 硬件优化&#xff1a;使用高性能的硬件设备&#xff0c;包括高速磁盘、大内存和高性能网络设备&#xff0c;以提高Kafka集群的整体性能。 配置优化&#xff1a;调整Kafka的配置参数&#xff0c;包括…

免费的爬虫软件【2024最新】

在国际市场竞争日益激烈的背景下&#xff0c;国外网站的SEO排名直接关系到网站在搜索引擎中的曝光度和用户点击量。良好的SEO排名能够带来更多的有针对性的流量&#xff0c;提升网站的知名度和竞争力。 二、国外网站SEO排名的三种方法 关键词优化&#xff1a; 关键词优化是SEO…

Red Hat Enterprise Linux 9.3 安装图解

引导和开始安装 选择倒计时结束前&#xff0c;通过键盘上下键选择下图框选项&#xff0c;启动图形化安装过程。需要注意的不同主板默认或者自行配置的固件类型不一致&#xff0c;引导界面有所不同。也就是说使用UEFI和BIOS的安装引导界面是不同的&#xff0c;如图所示。若手动调…