【Spring】循环依赖

目录标题

  • 什么是循环依赖
  • 循环依赖场景
  • Java SE 演示
  • Spring 容器演示
  • 三级缓存
    • 核心知识
      • 三级缓存
      • 四大方法
      • 三级缓存中的迁移
    • 三级缓存源码分析
    • 源码思维导图
  • 源码图例
  • 课前问题
  • 推荐阅读

  • 循环依赖是什么?
  • 循环依赖的场景有哪一些?
  • 三级缓存分别是什么?三个Map有什么异同?
  • 三级缓存是如何解决循环依赖的?
  • 为什么要使用三级缓存?为什么不可以用二级缓存?
  • 为什么构造器循环依赖、原型Bean循环依赖无法用三级缓存解决?
  • 看过 Spring源码吗?一般我们说的 Spring容器是什么?
  • 如何检测是否存在循环依赖?实际开发中见过循环依赖的异常吗?
  • 如果循环依赖的时候,所有类又都需要 Spring AOP自动代理,那Spring如何提前曝光?曝光的是 原始bean 还是 代理后的bean ?

https://docs.spring.io/spring-framework/reference/

image.png

什么是循环依赖

多个Bean互相引用,形成环路

循环依赖场景

  • 原型Bean的循环依赖
  • 单例bean之构造注入的循环依赖
  • 单例bean之setter注入的循环依赖

前两者无法解决,最后一种可以通过Spring提供的三级缓存来进行实现。

Java SE 演示

@Component
public class ServiceA {private ServiceB serviceB;public void setServiceB(ServiceB serviceB) {this.serviceB = serviceB;System.out.println("A 里面设置了B");}// public ServiceA(ServiceB serviceB) {//     this.serviceB = serviceB;// }
}
@Component
public class ServiceB {private ServiceA serviceA;public void setServiceA(ServiceA serviceA) {this.serviceA = serviceA;System.out.println("B 里面设置了A");}// public ServiceB(ServiceA serviceA) {//     this.serviceA = serviceA;// }
}
public class ClientDemo {public static void main(String[] args) {clientSet();// clientConstruct();}/*** setter注入*/private static void clientSet() {//创建serviceAServiceA serviceA = new ServiceA();//创建serviceBServiceB serviceB = new ServiceB();//将serviceA注入到serviceB中serviceB.setServiceA(serviceA);//将serviceB注入到serviceA中serviceA.setServiceB(serviceB);}/*** 构造注入*/private static void clientConstruct(){// new ServiceA(new ServiceB(new ServiceA(new ServiceB())));}
}

Spring 容器演示

<!--    <bean id="a" class="com.example.demo.circulardependency.spring.A" scope="singleton">--><bean id="a" class="com.example.demo.circulardependency.spring.A" scope="prototype"><property name="b" ref="b"/></bean><!--    <bean id="b" class="com.example.demo.circulardependency.spring.B" scope="singleton">--><bean id="b" class="com.example.demo.circulardependency.spring.B" scope="prototype"><property name="a" ref="a"/></bean>
public class ClientSpringContainer {public static void main(String[] args) {sampleDemo();}/*** spring** 2024/2/2 11:40*/private static void sampleDemo() {/*** setter注入* * 11:39:14.055 [main] DEBUG o.s.b.f.s.DefaultListableBeanFactory - Creating shared instance of singleton bean 'a'* ---A created success* 11:39:14.064 [main] DEBUG o.s.b.f.s.DefaultListableBeanFactory - Creating shared instance of singleton bean 'b'* ---B created success*//*** 构造注入* * Exception in thread "main" org.springframework.beans.factory.BeanCreationException:**/ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");A a = context.getBean("a", A.class);B b = context.getBean("b", B.class);}
}

三级缓存

Spring循环依赖 - CSDN博客

核心知识

三级缓存

一级缓存:Map<String, Object> singletonObjects,我愿称之为成品单例池,常说的 Spring 容器就是指它,我们获取单例 bean 就是在这里面获取的,存放已经经历了完整生命周期的Bean对象
二级缓存:Map<String, Object> earlySingletonObjects,存放早期暴露出来的Bean对象,Bean的生命周期未结束(属性还未填充完整,可以认为是 半成品的 bean, 实例化但未初始化的Bean对象
三级缓存:Map<String, ObiectFactory<?>> singletonFactories,存放可以生成Bean的工厂(FactoryBean),用于生产(创建)对象

/** Cache of singleton objects: bean name to bean instance. */
// 一级缓存:singleton对象的缓存:bean名称 - bean实例。
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);/** Cache of singleton factories: bean name to ObjectFactory. */
// 三级缓存:单例工厂的缓存:bean名称 - ObjectFactory
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);/** Cache of early singleton objects: bean name to bean instance. */
// 二级缓存:早期singleton对象的缓存:bean名称 - bean实例。
private final Map<String, Object> earlySingletonObjects = new HashMap<>(16);

四大方法

  1. getSingleton():从容器里面获得单例的bean,没有的话则会创建 bean
  2. doCreateBean():执行创建 bean 的操作(在 Spring 中以 do 开头的方法都是干实事的方法)
  3. populateBean():创建完 bean 之后,对 bean 的属性进行填充
  4. addSingleton():bean 初始化完成之后,添加到单例容器池中,下次执行 getSingleton() 方法时就能获取到

三级缓存中的迁移

  1. A创建过程中需要B,于是A将自己放到三级缓存里面,去实例化B
  2. B实例化的时候发现需要A,于是B先查一级缓存,没有,再查二级缓存,还是没有,再查三级缓存,找到了A,然后把三级缓存里面的这个A放到二级缓存里面,并删除三级缓存里面的A
  3. B顺利初始化完毕,将自己放到一级缓存里面(此时B里面的A依然是创建中状态),然后回来接着创建A,此时B已经创建结束,直接从一级缓存里面拿到B,然后完成创建,并将A自己放到一级缓存里面。

三级缓存源码分析

【Spring】三级缓存

源码思维导图

Spring三级缓存源代码执行图

源码图例

image.png

课前问题

在这里插入图片描述
还剩下三个:

  • 为什么不可以用二级缓存?这部分我在网上搜寻了一下,跟AOP的代理有关(由于目前我对AOP不熟,怕误导了大家,就先欠着)
  • 开发中解决循环依赖?欠着
  • 循环依赖遇上AOP?欠着

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

推荐阅读

  • Spring源码最难问题《当Spring AOP遇上循环依赖》_循环依赖aop在那个阶段-CSDN博客
  • spring 循环依赖以及解决方案(吊打面试官)_循环依赖解决方案-CSDN博客
  • spring循环依赖-CSDN博客

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

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

相关文章

openEuler学习——mysql(第一次总结)

1、openEuler 二进制方式安装MySQL 8.0.x。 思路是先从官网获取安装包链接如下https://mirrors.aliyun.com/mysql/MySQL-8.0/mysql-8.0.28-linux-glibc2.12-x86_64.tar.xz 然后解压安装修改权限&#xff0c;可以参考mysql官方网站步骤 [rootopenEuler-node1 ~]# wget -c https:…

DS:循环队列的实现

创作不易&#xff0c;给个三连吧&#xff01;&#xff01; 一、前言 对于循环队列&#xff0c;博主也是源自于一道力扣的OJ题 力扣&#xff1a;循环队列的设置 后来我在网上查过&#xff0c;这个循环队列是有自己的应用场景的&#xff01;&#xff01;并不是出题者为了出题…

网络防火墙综合实验

备注&#xff1a;电信网段15.1.1.0 移动网段14.1.1.0 办公区 11.1.1.0 生产区 10.1.1.0 服务区 13.1.1.0 公网 1.1.1.1 和 2.2.2.2 需求&#xff1a; 1、办公区设备可以通过电信链路和移动链路上网&#xff08;多对多nat&#xff0c;并且需要保留一个公网ip&#xff09; 2、…

<网络安全>《40 网络攻防专业课<第六课 - 木马与防范>》

1 木马 1.1 木马简介 木马是攻击者编写的一段恶意代码&#xff0c;它潜伏在被攻击者的计算机中。攻击者通过这个代码可远程控制被攻击者的计算机&#xff0c;以窃取计算机上的信息或者操作计算机。从本质上讲&#xff0c;木马也是病毒的一种&#xff0c;因此不少用户也把木马…

代码随想录算法训练营DAY20 | 二叉树 (8)

一、LeetCode 701 二叉搜索树中的插入操作 题目链接&#xff1a; 701.二叉搜索树中的插入操作https://leetcode.cn/problems/insert-into-a-binary-search-tree/description/ 思路&#xff1a;见缝插针罢辽。 class Solution {public TreeNode insertIntoBST(TreeNode root, i…

ChatGPT-01 用ChatGPT指令,自学任何领域的系统知识

1. 指令位置 Github仓库&#xff1a;Mr Ranedeer AI Tutor 但是需要开通chatgtp plus版本&#xff0c;并且打开代码解释器 2 使用 学习内容 开始学习 GPT甚至可以给你思考题&#xff0c;给出的答案还能进行评价 配置 通过配置表修改 深度 学习风格 沟通风格 语气风格 …

花费200元,我用全志H616和雪糕棒手搓了一台可UI交互的视觉循迹小车

常见的视觉循迹小车都具备有路径识别、轨迹跟踪、转向避障、自主决策等基本功能&#xff0c;如果不采用红外避障的方案&#xff0c;那么想要完全满足以上这些功能&#xff0c;摄像头、电机、传感器这类关键部件缺一不可&#xff0c;由此一来小车成本也就难以控制了。 但如果&a…

深度学习基础之《TensorFlow框架(3)—TensorBoard》

一、TensorBoard可视化学习 1、TensorFlow有一个亮点就是&#xff0c;我们能看到自己写的程序的可视化效果&#xff0c;这个功能就是TensorBoard 2、TensorFlow可用于训练大规模深度神经网络所需的计算&#xff0c;使用该工具涉及的计算往往复杂而深奥。为了方便TensorFlow程…

C++11---(2)

目录 一、新增容器 1.1、array 1.2、forward_list 1.3、unordered系列 二、右值引用和移动语义 2.1、什么是左值&#xff0c;什么是左值引用 2.2、什么是右值&#xff0c;什么是右值引用 2.3、左值引用和右值引用比较 2.4、右值引用使用场景和意义 2.5、右值引用引用…

EasyRecovery易恢复中文破解版2024最新破解序列号

EasyRecovery易恢复是一款来自美国的数据恢复软件&#xff0c;已有35年&#xff08;或38年&#xff09;的历史。它支持不同存储介质的数据恢复&#xff0c;包括电脑系统硬盘、移动硬盘等&#xff0c;并针对不同的数据丢失原因提供了相应的恢复方案。 EasyRecovery易恢复是一款功…

基于java的企业校园招聘平台的设计与实现

分享一个自己的毕业设计&#xff0c;想要获取源码的同学加V&#xff1a;qq2056908377 链接&#xff1a;https://pan.baidu.com/s/1It0CnXUvc9KVr1kDcHWvEw 提取码&#xff1a;1234 摘要&#xff1a; 摘要&#xff1a;本毕业设计旨在设计和实现一个企业校园招聘平台&#xf…

2024-02-19(Flume,DataX)

1.flume中拦截器的作用&#xff1a;个人认为就是修改或者删除事件中的信息&#xff08;处理一下事件&#xff09;。 2.一些拦截器 Host Interceptor&#xff0c;Timestamp Interceptor&#xff0c;Static Interceptor&#xff0c;UUID Interceptor&#xff0c;Search and Rep…

Query Rewrite —— 基于大模型的query扩展改写,如何减少LLM的幻觉问题,召回提升15%(北大论文)

北大论文&#xff0c;关于使用模型进行query扩展&#xff0c;提升召回率。并且合理解决模型的幻觉问题。 论文地址&#xff1a;SYNERGISTIC INTERPLAY BETWEEN SEARCH AND LARGE LANGUAGE MODELS FOR INFORMATION RETRIEVAL 一、论文的核心思想 如何有效的丰富扩展query&#…

Datawhale零基础入门金融风控Task1 赛题理解

Task1 赛题理解 Tip:本次新人赛是Datawhale与天池联合发起的0基础入门系列赛事第四场 —— 零基础入门金融风控之贷款违约预测挑战赛。 赛题以金融风控中的个人信贷为背景&#xff0c;要求选手根据贷款申请人的数据信息预测其是否有违约的可能&#xff0c;以此判断是否通过此项…

qt QTableWidget 表头没有间隔

使用时&#xff0c;发现表头没有间隔线 表头样式表设置为&#xff1a; /*设置表格整体样式*/ QTableView{border:1px solid #A1B7CF;background-color:#FFFFFF; /*注意&#xff1a;设置下面值时不要再设置background-color,不然会被覆,不信你试试看&#xff01;*/alternate-bac…

RHEL8提示需要注册才可以yum解决办法

关闭注册以及修改更新远&#xff08;已注册的RHEL8忽略本步骤&#xff09; 原因&#xff1a;因为没注册的红帽子是无法连接到官方的Yum源的 箭头所指的改成0 vi /etc/yum/pluginconf.d/subscription-manager.conf 箭头所指的改成0 cd /etc/yum.repos.d/ wget https://mirro…

DP读书:《openEuler操作系统》(十)套接字 Socket 数据传输的基本模型

10min速通Socket 套接字简介数据传输基本模型1.TCP/IP模型2.UDP模型 套接字类型套接字&#xff08;Socket&#xff09;编程Socket 的连接1.连接概述(1)基本概念(2)连接状态(3)连接队列 2.建立连接3.关闭连接 socket 编程接口介绍数据的传输1. 阻塞与非阻塞2. I/O复用 数据的传输…

虹科方案丨低负载ECU老化检测解决方案:CANCAN FD总线“一拖n”

来源&#xff1a;虹科汽车智能互联 虹科方案丨低负载ECU老化检测解决方案&#xff1a;CANCAN FD总线“一拖n” 原文链接&#xff1a;https://mp.weixin.qq.com/s/4tmhyE5hxeLFCiaeoRhlSg 欢迎关注虹科&#xff0c;为您提供最新资讯&#xff01; #汽车总线 #ECU #CAN卡 导读 …

Linix与Windows上使用nc命令测试某一个服务器端口网络是否正常可访问详细安装及测试步骤

一、windows 1、下载nc安装包 https://nszyf.lanzoum.com/ihtqS0v0lwwh 2、下载后解压放置在自己电脑合适的位置&#xff0c;并且配置到环境变量中 3、配置成功环境变量&#xff0c;winr打开运行&#xff0c;输入cmd&#xff0c;回车&#xff0c;打开一个终端测试 测试成功…

【9-1】实验——Neo4j实战操作

目录 一、Neo4j操作——CQL 1、常用CQL命令 2.常用CQL函数 3.图数据的形式 二、实战代码1.create命令 2. MATCH命令 三、使用neo4j工具导入知识图谱 1、工具&#xff1a;neo4j-admin 2、图谱导入&#xff1a; 3、更新图谱&#xff1a; 一、Neo4j操作——CQL 1、常用…