Spring循环依赖大全

news2024/11/23 7:00:32

本博客挑出出现大部分情况的循环依赖场景进行分析,分析启动会不会报循环依赖的错误!

一、常规的A依赖B,B依赖A,代码如下:

@Component
public class A {
    @Resource
    private B b;
}
@Component
public class B {
    @Resource
    private A a;
}

case1分析

答案是不会报错!!!因为sping已经通过三级缓存解决了这种循环依赖
在这里插入图片描述
将上面的抽象逻辑转化一下,其核心原理是通过无参构造方法 + set方法:
A a = new A();
B b = new B();
b.setA(a);
a.setB(b);

二、A和B都只有参构造

@Component
public class A {
    @Resource
    private B b;
    public A(B b){
       this.b = b;
    }
}
@Component
public class B {
    @Resource
    private A a;
    public B(A a){
       this.a = a;
    }
}

case2分析

答案是会报错!因为A和B的默认构造方法都被自定义的构造方法覆盖了!Spring就不会用clazz.getConstructor().newInstance()这个方法new出原始对象;他会进行构造器的推断,发现想创建A必须传入B,就会在IOC容器中找B对象,但b对象肯定没有就会尝试尝试创建b,创建b的时候又会被提示创建b,必须得先创建a…其实再第二次尝试创建a的时候就报错了!
在这里插入图片描述
在这里插入图片描述
将上面的抽象逻辑转化一下,陷入无限套娃模式,你发现你自己永远创建不了这个对象:
A a = new A( new B(new A( …) ) )
有点类似上面的感觉,但spring默认是单例肯定不会无限new

三、有一个类没有无参构造

@Component
public class A {
    @Resource
    private B b;
    public A(B b){
       this.b = b;
    }
    public A(){}
}
@Component
public class B {
    @Resource
    private A a;
    public B(A a){
       this.a = a;
    }
}

case3分析

得看创建顺序!如果先创建A,不会报错!如果先创建B,会爆循环依赖的错误!

1.先创建a的情况(没问题):

A a = new A();
B b = new B(a);
a.setB(b);

2.先创建b的情况:

new B(??) → 发现创建B之前得先有a 阻塞住!!!!
A a = new A() ;
//下面的两句spring不会执行
a.setB(new B(a));
b.setA(a);
虽然直观感觉可以往后走,但经过打断点哈,发现是在执行populateBean中的bean后置处理器报错了,为什么?????
具体的方法栈是:
org.springframework.context.annotation.CommonAnnotationBeanPostProcessor#postProcessProperties(这就是@Resource注解的后置处理器)
org.springframework.context.annotation.CommonAnnotationBeanPostProcessor.ResourceElement#getResourceToInject(false条件的语句)
org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#resolveBeanByName
org.springframework.beans.factory.support.AbstractBeanFactory#doGetBean
在这里插入图片描述
报错的根本原因a注入b属性的时候,发现123级缓存中都没有b,就会再次创建一个B,这对于单例Bean来说是不允许的!!!!你创建两个B对象,那么B对象就不是单例啊
在这里插入图片描述

四、@Async注解导致的循环依赖

@Component
public class A {
    @Autowired
    private B b;
    @Async //!!!!!!!
    public void test(){}
}
@Component
public class B {
    @Autowired
    private A a;
}

case4分析

1.先创建A会报错,下面是具体分析

在这里插入图片描述

下面这段代码就是再doCreateBean的最下方,是第一种情况的报错点!
spring在这里报错合理吗,大家思考一下:
在这里插入图片描述

2.先创建B就正常运行,下面是具体分析

在这里插入图片描述

如何解决这种循环依赖?????
方案1:在A类的b属性加上@Lazy注解,或者在B类的a属性加上@Lazy注解
方案2:让A类的scope指定为 prototype (不推荐!)

五、自定义AOP切面产生的循环依赖

@Component
public class A {
    @Autowired
    private B b;
    public void aoptest(){}
}
@Component
public class B {
    @Autowired
    private A a;
}
@Aspect
@Component
public class LzlAspect {
    @Pointcut("execution(public * com.lzl.circleRefrence.bean.A.aoptest())")
    public void pointCut(){
    }
    @Before("pointCut()")
    public void beforeInfo(){
        System.out.println("aaaa");
    }
}

case5分析

答案是不会报错!!
是不是感觉很奇怪?为什么case4有报错的情况,而这个也会产生aop代理对象,为什么不报错???
答案是:spring的三级缓存中存储的lamda表达式如下所示,该lamda表达式只会在出现循环依赖的时候执行,在这里可以提前进行aop,让二级缓存直接塞入代理对象
在这里插入图片描述
看到这里,是不是又出现一个新的问题:为什么自己写的切面可以提前aop,@Async注解的切面为什么不提前aop?????
我认为哈,这是Spring的一个遗憾,在上面这块代码中Async的后置处理器 不属于 SmartInstantiationAwareBeanPostProcessor 类,压根不会在这里进行aop代理
在这里插入图片描述

六、原型Bean的循环依赖

@Component
@Scope("prototype")
public class A {
    @Resource
    private B b;
}
@Component
@Scope("prototype")
public class B {
    @Resource
    private A a;
}

case6分析

答案是会报错!
在这里插入图片描述
1.A进行生命周期,实例化A
2.A依赖了B,进入到B的生命周期,B进行实例化
3.B又依赖了A,而且A又是个原型的bean,所以又要再创建一个A的bean进行注入
4.创建A的bean时,又遇到了跟B一样的问题,一直无穷无尽了
如何解决?????两个类中的属性都加上@Lazy
1.A进行生命周期,实例化A
2.A依赖了B,但是B是个懒加载的bean,创建一个代理返回给A
3.A的生命周期结束
4.B进行生命周期,实例化B
5.B依赖了A,但是A也是个懒加载对象,创建一个代理返回给B
6.B的生命周期结束
7.在A真正使用到B/B真正使用到A的时候,代理对象调用他的getObject方法,返回真正单例池里的真正对象,进行执行

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

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

相关文章

Codeforces Round 898 (Div. 4)

Dashboard - Codeforces Round 898 (Div. 4) - Codeforces F. Money Trees 双指针&#xff08;需要细心&#xff09; #include<bits/stdc.h> using namespace std; const int N 2e5 10; void solve() {int n, k, ans 0, a[N], h[N];cin >> n >> k;for(…

Java基础(五)

前言&#xff1a;本博客主要记录学习网络通信的基本知识以及网络编程的应用。 网络编程 基本的通信架构 CS架构&#xff08;Cilent客户端/Server服务端&#xff09; BS架构&#xff08;Browser浏览器/Server服务端&#xff09; 网络通信三要素 网络通信三要素&#xff1a;…

【02】FISCOBCOS搭建区块链网络

官方文档https://fisco-bcos-documentation.readthedocs.io/zh_CN/latest/docs/installation.html 第一步. 安装依赖 开发部署工具 build_chain.sh脚本依赖于openssl, curl&#xff0c;根据您使用的操作系统&#xff0c;使用以下命令安装依赖。 sudo apt install -y openssl …

【深度学习实验】前馈神经网络(九):整合训练、评估、预测过程(Runner)

目录 一、实验介绍 二、实验环境 1. 配置虚拟环境 2. 库版本介绍 三、实验内容 0. 导入必要的工具包 1. __init__(初始化) 2. train(训练) 3. evaluate(评估) 4. predict(预测) 5. save_model 6. load_model 7. 代码整合 一、实验介绍 二、实验环境 本系列实验使用…

latexocr安装过程中遇到的问题解决办法

环境要求&#xff1a;需要Python版本3.7&#xff0c;并安装相应依赖文件 具体的详细安装步骤可见我上次写的博文&#xff1a;Mathpix替代者|科研人必备公式识别插件|latexocr安装教程 ‘latexocr‘ 不是内部或外部命令&#xff0c;也不是可运行的程序或批处理文件的相关解决办…

获取文件创建时间

版权声明 本文原创作者&#xff1a;谷哥的小弟作者博客地址&#xff1a;http://blog.csdn.net/lfdfhl Java源码 public void testGetFileTime() {try {String string "E://test.txt";File file new File(string);Path path file.toPath();BasicFileAttributes ba…

Python 运行代码

一、Python运行代码 可以使用三种方式运行Python&#xff0c;如下&#xff1a; 1、交互式 通过命令行窗口进入 Python 并开始在交互式解释器中开始编写 Python 代码 2、命令行脚本 可以把代码放到文件中&#xff0c;通过python 文件名.py命令执行代码&#xff0c;如下&#xff…

Grafana离线安装部署以及插件安装

Grafana是一个可视化面板&#xff08;Dashboard&#xff09;&#xff0c;有着非常漂亮的图表和布局展示&#xff0c;功能齐全的度量仪表盘和图形编辑器&#xff0c;支持Graphite、zabbix、InfluxDB、Prometheus和OpenTSDB作为数据源。Grafana主要特性&#xff1a;灵活丰富的图形…

Idea远程调试Linux服务器(和docker容器)中的Java服务,实测可用

目录 idea远程调试linux上的java服务 idea远程调试linux上docker中的java服务 本地配置 打开设置 添加Remote 环境:java1.8 idea远程调试linux上的java服务 在远程Linux服务器上启动Java应用程序时&#xff0c;请使用以下命令行选项启用调试&#xff1a; java -agentlib:…

R3300L, Q7 ATV Android9固件

R3300L, Q7 ATV Android9固件 固件来源 https://www.znds.com/tv-1239603-1-1.html 之前在恩山上发布过1080p安卓6固件 https://www.right.com.cn/forum/thread-1761250-1-1.html, 这个固件的不足之处就是没有 Google Service Framework, 只能通过 Smart Youtube 之类的第三方…

Mac台式电脑内存清理方法教程

对于一些小白用户&#xff0c;如果觉得以上的清理方法比较复杂却又想要更好的优化Mac电脑内存&#xff0c;专业的系统清理软件是一个不错的选择。比起花几个小时时间浏览文件夹、删除临时文件、缓存和卸载残留。Cleanmymac X&#xff0c;只需单击几下即可完成所有内存清理工作&…

华为云:成就卓越企业,引领智能未来

编辑&#xff1a;阿冒 设计&#xff1a;沐由 “预感总是倏然来临&#xff0c;灵光一现&#xff0c;好像一种确凿无疑的信念在瞬间萌生却无从捕捉。”在其传世的《百年孤独》一书中&#xff0c;加西亚马尔克斯曾经这样写道。 如此笃信却无力的感觉&#xff0c;也让很多急于以数字…

Python_it_heima

P63 list P68 元组 注意&#xff1a;元组内部嵌套的list包含的内容可以修改&#xff0c;但list本身不能修改。 P69 字符串 P71 数据容器&#xff08;序列&#xff09;的切片 P73 集合 P75 字典 字典的常用操作 字典课后练习 P78 类数据容器的总结对比 P79 数据容器的通用操作 不…

ros2发布者节点

没有书看啊&#xff0c;就来看看这个代码吧&#xff1a; 首先&#xff1a;第一个函数&#xff1a;init&#xff0c;通过f12可以知道这个函数共有4个变量&#xff0c;前面2个就这么填&#xff0c;后面2个有默认值&#xff0c;不用管&#xff0c;所以一般这么写就好了。 spin函…

IDEA2023新UI回退老UI

idea2023年发布了新UI&#xff0c;如下所示 但是用起来真心不好用&#xff0c;各种位置也是错乱&#xff0c;用下面方法可以回退老UI

聊聊Spring的Aware接口

文章目录 0.前言1.什么是Aware接口2.Aware接口的设计目的3.详解3.1. ApplicationContextAware我们举个例子来说明 3.2. BeanFactoryAware3.3. BeanNameAware3.4. ServletContextAware3.5. MessageSourceAware3.6. ResourceLoaderAware 4.参考文档 0.前言 背景&#xff1a; 最近…

C语言数组和指针笔试题(三)(一定要看)

目录 字符数组四例题1例题2例题3例题4例题5例题6例题7 结果字符数组五例题1例题2例题3例题4例题5例题6例题7结果字符数组六例题1例题2例题3例题4例题5例题6例题7 结果 感谢各位大佬对我的支持,如果我的文章对你有用,欢迎点击以下链接 &#x1f412;&#x1f412;&#x1f412;个…

建构居住安全生态,鹿客科技2023秋季发布会圆满举办

9月20日&#xff0c;以「Lockin Opening」为主题的2023鹿客秋季发布会在上海隆重举办&#xff0c;面向居住安全领域鹿客带来了最新的高端旗舰智能锁新品、多眸OS1.0、Lockin Care服务以及全联接OPENING计划。此外&#xff0c;现场还邀请了国家机构、合作伙伴、技术专家等业界同…

ai智能生成文章-智能生成文章软件

您是否曾为创作内容而感到头疼不已&#xff1f;是否一直在寻找一种能够帮助您轻松生成高质量文章的解决方案&#xff1f;什么是AI智能生成文章&#xff0c;特别是147SEO智能原创文章生成。这是一种先进的技术&#xff0c;利用人工智能和自然语言处理&#xff0c;能够自动生成各…

Ant Design分页组件中实现禁止点击当前页按钮的方法

这里需要使用到Ant Design分页组件pagination的一个回调函数onChange onChange函数用来监听鼠标点击事件&#xff0c; 它有两个入参》1. 点击分页按钮时获取到的页码 2. 每页最大显示条数 所以&#xff0c;禁止点击当前分页按钮的核心逻辑是&#xff1a; if {当前页的页…