Spring循环依赖大全

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

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

@Component
public class A {@Resourceprivate B b;
}
@Component
public class B {@Resourceprivate 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 {@Resourceprivate B b;public A(B b){this.b = b;}
}
@Component
public class B {@Resourceprivate 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 {@Resourceprivate B b;public A(B b){this.b = b;}public A(){}
}
@Component
public class B {@Resourceprivate 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 {@Autowiredprivate B b;@Async //!!!!!!!public void test(){}
}
@Component
public class B {@Autowiredprivate 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 {@Autowiredprivate B b;public void aoptest(){}
}
@Component
public class B {@Autowiredprivate 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 {@Resourceprivate B b;
}
@Component
@Scope("prototype")
public class B {@Resourceprivate 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.rhkb.cn/news/139669.html

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

相关文章

【Java 基础篇】Java函数式接口详解

Java是一门强类型、面向对象的编程语言,但在Java 8引入了函数式编程的概念,这为我们提供了更多灵活的编程方式。函数式接口是函数式编程的核心概念之一,本文将详细介绍Java函数式接口的概念、用法以及一些实际应用。 什么是函数式接口&#…

mall电商项目(学习记录1)

1.简介 mall项目是一套电商系统,包括前台商城系统及后台管理系统,基于SpringBoot+MyBatis实现,采用Docker容器化部署。前台商城系统包含首页门户、商品推荐、商品搜索、商品展示、购物车、订单流程、会员中心、客户服务、帮助中心等模块。后台管理系统包含商品管理、订单管…

一、 计算机网络概论

一、计算机网络概论 1、计算机网络概述 1.1、概念 计算机网络是一个将分散的、具有独立功能的计算机系统,通过通信设备与线路连接起来,由功能完善的软件实现资源共享和信息传递的系统 是一些互连的、自治的计算机系统的集合 以能够相互共享资源的方…

Python函数绘图与高等代数互融实例(八):箱线图|误差棒图|堆积图

Python函数绘图与高等代数互融实例(一):正弦函数与余弦函数 Python函数绘图与高等代数互融实例(二):闪点函数 Python函数绘图与高等代数互融实例(三):设置X|Y轴|网格线 Python函数绘图与高等代数互融实例(四):设置X|Y轴参考线|参考区域 Python函数绘图与高等代数互融实例(五…

蓝桥杯 题库 简单 每日十题 day7

01 啤酒和饮料 题目描述 本题为填空题,只需要算出结果后,在代码中使用输出语句将所填结果输出即可。啤酒每罐2.3元,饮料每罐1.9元。小明买了若干啤酒和饮料,一共花了82.3元。我们还知道他买的啤酒比饮料的数量少,请你…

C/C++运算符超详细讲解(系统性学习day5)

目录 前言 一、运算符的概念与分类 二、算术运算符 三、关系运算符 四、逻辑运算符 五、赋值运算符 六、运算符的优先级 总结 前言 本篇文章是对运算符的具体讲解。 一、运算符的概念与分类 概念: 运算符就是一种告诉编译器执行特定的数学或逻辑操作的符…

红黑树Java实现

文章目录 红黑树1. 概念性质2. 红黑树节点定义3. 红黑树的插入情况1情况2情况3其它细节问题插入代码实现 4. 红黑树的验证5.性能分析 红黑树 1. 概念性质 红黑树也是一种二插搜索树,每一个节点上比普通二插搜索树都增加了一个存储位置表示节点的颜色,可…

【已解决】ubuntu 16.04安装最新版本google chrome出错, 旧版本chrome浏览器安装流程

ubuntu 16.04 按照常规的Chrome 安装流程总是出错如下: Selecting previously unselected package google-chrome-stable. (Reading database ... 231747 files and directories currently installed.) Preparing to unpack google-chrome-stable_current_amd64.de…

自己写过比较蠢的代码:从失败中学习的经验

文章目录 引言1. 代码没有注释2. 长函数和复杂逻辑3. 不恰当的变量名4. 重复的代码5. 不适当的异常处理6. 硬编码的敏感信息7. 没有单元测试结论 🎉 自己写过比较蠢的代码:从失败中学习的经验 ☆* o(≧▽≦)o *☆嗨~我是IT陈寒🍹✨博客主页&a…

msvcr71.dll、msvcp71.dll丢失怎么办?快速修复方法分享

msvcr71.dll 是一个动态链接库文件,它包含了 C 运行时库的一些函数和类,例如全局对象、异常处理、内存管理、文件操作等。它是 Visual Studio 2003 及以上版本中的一部分,用于支持 C 应用程序的运行。如果 msvcr71.dll 丢失或损坏&#xff0c…

新手学习:ArcGIS对shp文件裁剪

新手学习:ArcGIS对SHP文件裁剪 新手学习 记录每个步骤,因为有很多控件可能刚开始还不熟悉,根本不知道在哪里,所以写的比较详细。 1.添加要裁剪的shp文件 2.查看shp文件的地理坐标系 双击shp文件,就可以查看shp文件的…

倒置字符串(牛客)

一、题目 二、代码 #include <iostream> #include<string> using namespace std;int main() {string s;getline(cin, s);string s2;int i s.length() - 1;int prev i;int next 0;while (i > 0 && prev > 0) { //从字符串的最后往前遍历if (s[pre…

React+Node——next.js 构建前后端项目

一、安装全局依赖 npm i -g create-next-app二、创建next项目 create-next-app react-next-demo //或 create-next-app react-next-demo --typescript三、加载mysql依赖 npm i -S mysql2四、运行项目 npm run dev五、创建db文件目录&#xff0c;目录下创建index.ts import…

HTML常用基本元素总结

<!DOCTYPE html> <html> <head> <meta charset"utf-8"> <title> biao qian</title> </head> <body><h1>这是标题1</h1> <h2>这是标题2</h2> <h3>这是标题3</h3><p> 这…

负载均衡 —— SpringCloud Netflix Ribbon

Ribbon 简介 Ribbon 是 Netfix 客户端的负载均衡器&#xff0c;可对 HTTP 和 TCP 客户端的行为进行控制。为 Ribbon 配置服务提供者地址后&#xff0c;Ribbon 就可以基于某种负载均衡算法自动帮助服务消费者去请求。Ribbon 默认提供了很多负载均衡算法&#xff0c;例如轮询、随…

IAP固件升级分几步?(Qt上位机、)

前言 这周一直想做一个IAP固件升级的上位机&#xff0c;然后把升级流程全都搞懂 有纰漏请指出&#xff0c;转载请说明。 学习交流请发邮件 1280253714qq.com IAP原理 IAP的原理我就不多赘述了&#xff0c;这里贴上几位大佬的文章 STM32CubeIDE IAP原理讲解&#xff0c;及U…

学会使用Git 和 GitHub

Git 和 GitHub 都是程序员每天都要用到的东西 —— 前者是目前最先进的 版本控制工具&#xff0c;拥有最多的用户&#xff0c;且管理着地球上最庞大的代码仓库&#xff1b;而后者是全球最大 同性交友 代码托管平台、开源社区。 在没有这两个工具时&#xff0c;编程可能是这样的…

驱动代码整理

一&#xff0c;控制LED灯控制实验 头文件 #ifndef __HEAD_H__ #define __HEAD_H__#define LED1_MODER 0X50006000 #define LED1_ODR 0X50006014 #define LED1_RCC 0X50000A28#endif 驱动 #include <linux/init.h> #include <linux/module.h> #include &l…

洛谷刷题入门篇:分支结构

今天又来了&#xff0c;刷题刷题&#xff0c;我爱刷题&#xff0c;题单链接如下&#xff1a; https://www.luogu.com.cn/training/101#problems 一、【深基1-2】小学数学 N 合一 题目如下&#xff1a;https://www.luogu.com.cn/problem/P2433 题目描述 问题 1 请输出 I lov…