spring 的循环依赖以及spring为什么要用三级缓存解决循环依赖

这篇具有很好参考价值的文章主要介绍了spring 的循环依赖以及spring为什么要用三级缓存解决循环依赖。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

知识铺垫

        bean的生命周期

        这里简单过一下

class ->无参构造 ->普通对象 ->依赖注入(对加了autowire等的属性赋值) ->初始化前->初始化 ->初始化后(aop) ->放入单例池的map(一级缓存) ->bean对象

这里提一点单例bean单例bean 其实就是用map<beanName,Bean对象>创建的,多例bean就不用map

循环依赖

现在有A类和B类,A持有B的引用,B持有A的引用,这就是循环依赖。如果没有Spring,我们又是如何去解决循环依赖呢。注意autowire的内部属性required默认为ture代表这个对象一定要有,不能给他设为null,所有在依赖注入的时候他就一定要有B对象,而B呢一定要有A对象

自己调用自己也算是循环依赖

@Test
	public void testCircle() throws Exception {
		TestA a = new TestA();
		TestB b = new TestB();	
		b.setTestA(a);
		a.setTestB(b);
	}

spring解决循环依赖的原理

spring解决循环依赖也是如此,首先暴露一个未初始化的实例TestA放到缓存中,创建TestB的实例时,获取的是TestA的未初始化对象,TestB创建完成以后,将TestA进行初始化,由于TestB中TestA的引用和TestA是一样的,TestB中的属性也是完全的初始化的

 三级缓存

DefaultSingletonBeanRegistry中存在三个Map,用作三级缓存。
一级缓存:singletonObjects ,用于保存BeanName与创建bean实例。(存放最终的bean)
二级缓存:earlySingletonObjects ,用于BeanName与创建bean实例,与singletonObjects 不同的是earlySingletonObjects 中存放的bean是一个未初始化的bean。(下文有讲解)
三级缓存:singletonFactories ,用于存放BeanName与bean工厂。打破循环
 

/** Cache of singleton objects: bean name --> bean instance */
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<String, Object>(256);

/** Cache of singleton factories: bean name --> ObjectFactory */
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<String, ObjectFactory<?>>(16);

/** Cache of early singleton objects: bean name --> bean instance */
private final Map<String, Object> earlySingletonObjects = new HashMap<String, Object>(16);

解决循环依赖就是要打破循环

出现循环依赖了就要提前进行aop

首先我们放在spring容器中的bean是单例的也就是唯一的,当我们出现循环依赖的时候,不如说a b两个类进行了互相调用还交给了spring管理,那么在生程a的时候 回去spring容器中去找b,而此时发现b 还没有创建(此时呢a就被放到了第二级缓存中,属性还没注入呢,就先拿来用了),那么就开始创建b (此时呢 a, 和b只是个普通对象,还没生产bean对象)那么创建b的时候呢,先去singletonObjects 这个map里去找,发现没有(当然创建a的时候们也会先去这去找),在判断a是否在创建,发现a在创建,就去第二级缓存中找,找到了这个a的提前使用的普通对象,就把他那拿到手,为什么这时候不能把他给bean对象呢?按照生命周期应该是这时候成为bean的呀,是因为我们生成的是单例bean 而如果他又aop操作的时候就又会生成代理对象给spring,那这样就不是单例了呀,那么这时候就把aop操作提前,再交给spring。而以上说的这个aop是怎么提前的呢,就是第三级缓存来判断生成额。第三集缓存主要是一个lamada表达式

在这里呢我理解的spring解决循环依赖,其实就是再bean的生命周期时,提前去用生成的这个生成的普通对象,然后最后依赖注入属性值,生成bean对象(其实两级缓存就可以了)

第二级缓存的作用,就是存储那些提前给别人去用的单例bean

三层缓存的关键不是保存前期的bean对象,而是打破循环,其实这个第三级缓存呢就是去打破这个循环的,比如说我们在一个依赖循环中需要一个a,我们在一二级缓存中找不到他的任何bean啊,早期bean啊,这时候我们可以认为这个第三级缓存就是提供这个a的

如果真的找到第三级缓存了,那么他回去判断你要不要aop如果不要aop 我原封不动的把你返回,如果要我返回你的代理对象,然后再放到二级缓存去

必须要第三级缓存判断aop,而且进入第三级缓存没有附加的条件去判断近不近,只要从第二级找不着,就进入三级缓存

spring 的循环依赖以及spring为什么要用三级缓存解决循环依赖,spring,spring,缓存,java

 如何去判断某个bean有没有提前进行aop这样你初始化后就不会了

spring 的循环依赖以及spring为什么要用三级缓存解决循环依赖,spring,spring,缓存,java

spring 的循环依赖以及spring为什么要用三级缓存解决循环依赖,spring,spring,缓存,java

这两个图中的字段

 解决不了的依赖注入

 spring 的循环依赖以及spring为什么要用三级缓存解决循环依赖,spring,spring,缓存,java

 spring 的循环依赖以及spring为什么要用三级缓存解决循环依赖,spring,spring,缓存,java

 这样的循环解决不了,这是在实例化的时候就出现了循环依赖,连对象都创建不了,咋办不行呗

他这个构造方法的过,你构造a的时候需要b,而你构造b的时候需要a。加个空参构造是可以的。

用@lazy 能解决吗

spring 的循环依赖以及spring为什么要用三级缓存解决循环依赖,spring,spring,缓存,java

 加了lazy,spring会直接给生成一个代理对象,跟aop没关系文章来源地址https://www.toymoban.com/news/detail-609518.html

至此结束,关于lazy如何生成代理对象,肥春本章不做讲解

到了这里,关于spring 的循环依赖以及spring为什么要用三级缓存解决循环依赖的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 为什么要用B+树

    B+树的优势 支持范围查询:B+树在进行范围查询时,只需要从根节点一直遍历到叶子节点,因为数据都存储在叶子节点上,而且叶子节点之间有指针连接,可以很方便的进行范围查询 支持排序:B+树的叶子节点按照顺序存储,可以快速支持排序操作,提供排序效率 存储

    2024年01月20日
    浏览(50)
  • 为什么要用开源容器?

    说到开源容器,大家首先想起来的应该是Docker吧,那么我们就以Docker来从个人角度理解一下为什么要用开源容器。 通常都会说Docker开源容器,但是Docker 实际上是一个开源的应用容器引擎。Docker是一个基于轻量级虚拟化技术的容器,整个项目基于Go语言开发,并采用了Apache 2

    2024年04月16日
    浏览(60)
  • 为什么要用虚拟 DOM?

    虚拟DOM(Virtual DOM)是一种将应用程序的状态(state)与DOM分离的技术。它是一个JavaScript对象,它的结构类似于实际DOM元素的结构。使用虚拟DOM的目的是在减少DOM操作的数量的同时,提高应用程序的性能和响应速度。 当应用程序的状态发生变化时,使用虚拟DOM可以计算出需要

    2024年02月01日
    浏览(48)
  • 低代码是什么意思?企业为什么要用低代码平台?

    低代码是什么意思?企业为什么要用低代码平台? 这两个问题似乎困扰了很多人,总有粉丝跟小简抱怨, 一天到晚念叨低代码,倒是来个人解释清楚啊! 来了,这次一文让你全明白。 在此之前,先了解什么是云计算。 “云” :指的就是互联网,因为之前互联网(Internet)

    2024年02月07日
    浏览(57)
  • 2023-06-03:redis中pipeline有什么好处,为什么要用 pipeline?

    2023-06-03:redis中pipeline有什么好处,为什么要用 pipeline? 答案2023-06-03: Redis客户端执行一条命令通常包括以下四个阶段: 1.发送命令:客户端将要执行的命令发送到Redis服务器。 2.命令排队:Redis服务器将收到的命令放入队列中,按照先进先出(FIFO)的原则等待执行。 3.命令

    2024年02月07日
    浏览(42)
  • bash脚本if语句比较为什么要用x

    如下进行PCIe设备的检测和计数,并执行重启操作的例子代码: 在给定的代码片段中,使用 x 是为了避免在比较时出现空字符串的问题。这是一种常见的技巧,用于确保比较操作的准确性。 在这个特定的语句中, x${devIDFunc0} 是用来检查变量 devIDFunc0 是否为空字符串。通过在变

    2024年02月08日
    浏览(53)
  • 在Vue中动态引入图片为什么要用require

    静态资源和动态资源 静态资源 动态的添加src 动态资源 我们通过网络请求从后端获取的资源 动态的添加src会被当成静态资源 动态的添加src最终会被打包成: 动态的添加图片最会会被编译成一个静态的字符串,然后再浏览器运行中会去项目中查找这个资源, 静态资源编译 默

    2024年02月13日
    浏览(51)
  • 为什么爬虫要用高匿代理IP?高匿代理IP有什么优点

    只要搜代理IP,度娘就能给我们跳出很多品牌的推广,比如我们青果网路的。 正如你所看到的,我们厂商很多宣传用词都会用到高匿这2字。 这是为什么呢?高匿IP有那么重要吗? 这就需要我们从HTTP代理应用最多最广的:爬虫数据采集来说。 爬虫数据采集的时候,非常容易遇

    2024年02月12日
    浏览(51)
  • facebook多账号运营为什么要用静态住宅ip代理?

    在进行Facebook群控时,ip地址的管理是非常重要的,因为Facebook通常会检测ip地址的使用情况,如果发现有异常的使用行为,比如从同一个ip地址频繁进行登录、发布内容或者在短时间内进行大量的活动等等,就会视为垃圾邮件或者恶意行为,导致账户被禁用或者限制。 因此,

    2024年02月21日
    浏览(48)
  • 模型\视图一般步骤:为什么经常要用“选择模型”QItemSelectionModel?

                                                              一、“使用视图”一般的步骤: //1. 创建  模型(这里是数据模型!) tabModel = new QSqlTableModel ( this , DB ); // 数据表 //2. 设置  视图 的 模型(这里是数据模型!) ui - tableView - setModel ( tabModel ); 模

    2024年01月22日
    浏览(56)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包