springIoc依赖注入循环依赖三级缓存

springIoc的理解,原理和实现

控制反转:

理论思想,原来的对象是由使用者来进行控制,有了spring之后,可以把整个对象交给spring来帮我们进行管理

依赖注入DI:

依赖注入,把对应的属性的值注入到具体的对象中,@autowired,populateBean完成属性的注入

容器

beanFactory,存储对象,使用map结构来存储,在spring中一般存在三级缓存,singletonObjects存放完整的bean对象,整个bean的生命周期,从创建初始化使用到销毁的过程都是容器来管理的

1,一般ioc容器的时候设计到容器的创建过程(beanFactory,DefaultListableBeanFactory)
2,加载解析bean对象,准备要创建的bean对象的定义对象 beanDefinition(xml或者注解的解析过程)
3,beanFactoryPostProcessor的处理,此处是扩展点,PlaceHolder
ConfigurSupport,ConfigurationClassProcessor.
4,BeanPostProcessor的注册功能,方便后续bean对象完成具体的扩展对象。
5,通过反射的方式将BeanDefinition对象实例化成具体的bean对象。
6,bean对象的初始化过程(填充属性,调用aware的子类方法,调用BeanPostProcessor前置处理方法,调用init-method方法,BeanPostProcessor的后置处理方法)

描述一下bean的生命周期

1,实例化bean,反射的方式生成对象
2,填充bean的属性:populateBean(),循环依赖的问题(三级缓存)
3,调用aware接口相关的方法:invokeAwareMethod(完成beanName可以获取容器bean的名称,BeanFactory获取当前bean factory这也可以调用容器的服务,BeanClassLoader对象的属性设置)
4,调用BeanPostProcessor中的前置方法:使用比较多的ApplicationContextPostProcessor设置ApplicationContext,Environment,ResourceLoader,EmbeddValueResolver等对象。
5,调用initmethod方法:invokeInitmethod(),判断是否实现了IntialzingBean接口,如果有,调用afterPropertiesSet方法。
6,调用BeanPostProceessor的后置处理方法:spring的aop就是在此实现的,AbstractAutoProxyCreator注册Destuction相关的回调接口。
7,通过getbean获取完整对象
8.销毁 判断是否实现了DisposableBean接口 destroyMethod方法
请添加图片描述

请添加图片描述

循环依赖

什么是循环依赖:

第一种互相依赖:A 依赖 B,B 又依赖 A,它们之间形成了循环依赖

在这里插入图片描述

第二种三者之间的依赖 A依赖B,B依赖C,C依赖A

在这里插入图片描述

第三种是自我依赖:A依赖A形成了循环依赖

在这里插入图片描述

三级缓存

  1. singletonObjects:缓存某个beanName对应的经过了完整生命周期的bean
  2. earlySingletonObjects:缓存提前拿原始对象进行了AOP之后得到的代理对象,原始对象还没有进行属性注入和后续的BeanPostProcessor等生命周期
  3. singletonFactories:缓存的是一个ObjectFactory,主要用来去生成原始对象进行了AOP之后得到的代理对象,在每个Bean的生成过程中,都会提前暴露一个工厂,这个工厂可能用到,也可能用不到,如果没有出现循环依赖依赖本bean,那么这个工厂无用,本bean按照自己的生命周期执行,执行完后直接把本bean放入singletonObjects中即可,如果出现了循环依赖依赖了本bean,则另外那个bean执行ObjectFactory提交得到一个AOP之后的代理对象(如果有AOP的话,如果无需AOP,则直接得到一个原始对象)。
public class DefaultSingletonBeanRegistry extends SimpleAliasRegistry implements SingletonBeanRegistry {/** Cache of singleton objects: bean name to bean instance. */private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);/** Cache of singleton factories: bean name to ObjectFactory. */private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);/** Cache of early singleton objects: bean name to bean instance. */private final Map<String, Object> earlySingletonObjects = new ConcurrentHashMap<>(16);
}

能否把一级缓存和二级缓存合并,只保留一个map结构来完成类似的功能?

理论上是可行的,一级缓存和二级缓存的value类型都是Object,都可以用来存放对象,只是对象的状态不同而已,所以当使用一个map的时候,只要给定具体的标识就可以解决这个问题,也就是说设置对象的时候,在value中不再直接存放对象,而是对象加标识位,比如0代表成品,1代表半成品,那么一个map就可以存储成品对象和办成品对象了,但是虽然可以这么干,没人会这么做,代码不优雅,而且每次在进行对象的存或者放的时候都要判断是否是成品对象,比较麻烦,直接用两个map结构解决即可

如果只有一级缓存和二级缓存,能否解决循环依赖的问题?

可以,但是有前提条件:没有aop的配置或者不需要创建代理对象的时候,两个map就可以解决循环依赖的问题

为什么三级缓存可以解决aop下的循环依赖问题?三级缓存到底有什么作用?

1,在同一个容器中,能否出现同名的不同对象?
不能,id是唯一标识

2,在同一个容器中,按照标准的生命周期,先创建了原始对象,后续又创建了代理对象,那时会怎么办?
当创建了代理对象之后,应该要使用代理对象的,但是原始对象已经存在,那么应该将原始对象给覆盖掉。getEarlyBeanReference()方法执行的逻辑是一样的

3,三级缓存到底有什么作用,为什么存在代理对象的时候就要使用三级缓存呢?
在标准的bean的生命周期中,要先创建出原始对象,创建出原始对象之后要使用populateBean方法来完成属性的赋值,此时赋值的对象是原始对象,因为代理对象还没有创建,代理对象的创建步骤是在BeanPostProcessor的后置处理方法中,也就是说已经完成赋值之后代理对象才创建出来,所以会报错(this means that said other beans do not use the final version of the bean),如何解决这个问题呢?

需要将代理对象的创建前置,也就是说在对象赋值的那一刻,要唯一性的确定出到底是原始对象还是代理对象,所以会优先把所有的bean都放到三级缓存中,在需要进行对象赋值的时候,从三级缓存中取出lambda表达式,lambda表达式的执行逻辑就是确定原始对象还是代理对象。如果是原始对象就赋值原始对象,如果是代理对象就赋值代理对象。

Spring中哪些情况下,不能解决循环依赖问题?

1,多例Bean通过setter注入的情况,不能解决循环依赖的问题。
当两个多例Bean相互依赖并且使用 Setter 方法注入时,Spring容器无法解决循环依赖。这是因为在多例模式下,每次请求获取一个新的Bean实例,Spring容器无法在创建Bean之前就确定依赖关系。
2,构造器注入的bean情况,不能解决循环依赖的问题。
循环依赖的产生:循环依赖通常在Bean的创建阶段发生,而构造器注入是在Bean创建之前发生的,因此无法通过构造器注入的方式解决已经发生的循环依赖。
3,设置了@DependsOn的Bean情况,不能解决循环依赖的问题。

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

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

相关文章

生成式AI,发展可持续吗?

最近有消息透露&#xff0c;OpenAI预计在2024年实现16亿美元的年化收入。相较于去年10月预测的13亿美元&#xff0c;这一数字增长了3亿美元&#xff0c;增长部分主要来源于ChatGPT订阅、API接入以及其他业务。 与此同时&#xff0c;其竞争对手Anthropic预计年化收入至少为8.5亿…

代码随想录算法训练营第三天 | 203.移除链表元素、707.设计链表、206.反转链表

代码随想录算法训练营第三天 | 203.移除链表元素、707.设计链表、206.反转链表 文章目录 代码随想录算法训练营第三天 | 203.移除链表元素、707.设计链表、206.反转链表1 链表理论基础1.1 链表的定义1.2 链表的类型1.3 链表的存储方式1.4 链表的操作性能分析1.5 链表和数组的区…

结队编程 - 华为OD统一考试

OD统一考试 题解: Java / Python / C++ 题目描述 某部门计划通过结队编程来进行项目开发,已知该部门有 N 名员工,每个员工有独一无二的职级,每三个员工形成一个小组进行结队编程,结队分组规则如下: 从部门中选出序号分别为 i、j、k 的3名员工,他们的职级分别为 level[…

JavaScript保留字和预定义的全局变量及函数汇总

保留字也称关键字&#xff0c;每种语言中都有该语言本身规定的一些关键字&#xff0c;这些关键字都是该语言的语法实现基础&#xff0c;JavaScript中规定了一些标识符作为现行版本的关键字或者将来版本中可能会用到的关键字&#xff0c;所以当我们定义标识符时就不能使用这些关…

乱码问题汇总

写在前面 在工作中经常会碰到各种莫名其妙的乱码问题&#xff0c;但通过之前的学习&#xff1a;字符集&字符编码-CSDN博客 &#xff0c;可以知道乱码的根本原因就是使用和数据源编码不一样的编码解码导致。 如&#xff1a;BIG5解码GB2312编码内容&#xff0c;编解码不一致…

【二十】【动态规划】879. 盈利计划、377. 组合总和 Ⅳ、96. 不同的二叉搜索树 ,三道题目深度解析

动态规划 动态规划就像是解决问题的一种策略&#xff0c;它可以帮助我们更高效地找到问题的解决方案。这个策略的核心思想就是将问题分解为一系列的小问题&#xff0c;并将每个小问题的解保存起来。这样&#xff0c;当我们需要解决原始问题的时候&#xff0c;我们就可以直接利…

【UE Niagara学习笔记】07 - 火焰的热变形效果

目录 效果 步骤 一、创建热变形材质 二、添加新的发射器 2.1 设置粒子材质 2.2 设置粒子初始大小 2.3 设置粒子持续生成 三、修改材质 四、设置粒子效果 在上一篇博客&#xff08;【UE Niagara学习笔记】06 - 制作火焰喷射过程中飞舞的火星&#xff09;的基础上继续…

codeql基本使用

0x01 安装codeql 去github下载一个对应版本的codeql捆绑包。 https://github.com/github/codeql-action/releases 然后解压&#xff0c;这里我是解压到桌面 然后用添加到环境变量中 然后在任意位置输入codeql命令&#xff0c;如果能有以下提示就表示安装成功 然后下载vscode…

PCAN数据速率分配

BitrateFD b"f_clock_mhz80, nom_brp8, nom_tseg116, nom_tseg23, nom_sjw1, data_brp4, data_tseg17, data_tseg22, data_sjw1" 在PCANBasic.py提供的example里有几个pcan收发的python程序,配置BitrateFD 后边丝毫看不出配置的Normal Bit Rate与 Data Bit Rate, …

在 Nvidia Docker 容器编译构建显存优化加速组件 xFormers

本篇文章&#xff0c;聊聊如何在新版本 PyTorch 和 CUDA 容器环境中完成 xFormers 的编译构建。 让你的模型应用能够跑的更快。 写在前面 xFormers 是 FaceBook Research &#xff08;Meta&#xff09;开源的使用率非常高的 Transformers 加速选型&#xff0c;当我们使用大模…

7.11、Kali Linux中文版虚拟机安装运行教程

目录 一、资源下载准备工作 二、安装教程 三、kali linux换源 四、apt-get update 报错 一、资源下载准备工作 linux 中文版镜像历史版本下载:http://old.kali.org/kali-images/ 大家可以自行选择版本下载&#xff0c;本人下载的是2021版本 二、安装教程 打开vmvare wokst…

鸿蒙基础开发实战-(ArkTS)像素转换

像素单位转换API的使用 主要功能包括&#xff1a; 展示了不同像素单位的使用。展示了像素单位转换相关API的使用。 像素单位介绍页面 在像素单位介绍页面&#xff0c;介绍了系统像素单位的概念&#xff0c;并在页面中为Text组件的宽度属性设置不同的像素单位&#xff0c;fp…