Spring 的三级缓存机制

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

Spring 的三级缓存机制

Spring 的三级缓存机制是解决循环依赖的关键

Spring 框架为了解决循环依赖问题,设计了一套三级缓存机制。这三级缓存分别是:

  1. 一级缓存 singletonObjects:这是最常规的缓存,用于存放完全初始化好的 bean。如果某个 bean 已经在这个缓存中,则直接返回这个 bean 的实例。
  2. 二级缓存 earlySingletonObjects:这个缓存用于存放早期暴露出来的 bean,也就是那些已经创建但尚未完成初始化(如属性填充和初始化方法调用)的 bean。这样做的目的是为了在 bean 的创建过程中就能提前暴露出来,以便于解决循环依赖的问题。
  3. 三级缓存 singletonFactories:这个缓存存放的是 bean 的工厂对象,这些工厂对象负责生成 bean 的实例。当一个 bean 被创建时,它的工厂对象会被放入这个缓存中。

通过这三级缓存,Spring 能够在 bean 的创建过程中就解决循环依赖的问题。具体来说,当 AOP 代理对象需要引用其他 bean 时,可以通过提前暴露的二级缓存来获取尚未完全初始化的 bean,从而打破循环依赖的僵局。

以下是一个简单的例子来说明这个过程:

假设有两个 bean,A 和 B,它们相互依赖。当 Spring 容器开始创建 bean A 时,它会首先检查一级缓存中是否已经有了 bean A 的实例。如果没有,它会创建一个 bean A 的实例,并将其工厂对象放入三级缓存中。然后,bean A 的创建过程会因为需要注入 bean B 而被挂起,Spring 会转而去创建 bean B。

在创建 bean B 的过程中,同样会检查一级缓存中是否已经有了 bean B 的实例。由于还没有创建,Spring 会将 bean B 的半成品(即尚未完成初始化的实例)放入二级缓存中,并继续创建过程。这时,bean B 也需要依赖 bean A,但由于 bean A 的工厂对象已经在三级缓存中,Spring 可以直接从三级缓存中获取到 bean A 的工厂对象,并通过它来创建 bean A 的实例。

这样,即使两个 beans 相互依赖,Spring 也能够通过三级缓存机制成功地创建它们,解决了循环依赖的问题。

spring三级缓存,Java,spring,缓存,java

参考文章——Spring中的“三级缓存”

参考文章——Spring面试题之循环依赖与三级缓存

为什么 Spring 只有二级缓存不行

Spring只有二级缓存确实无法完全解决循环依赖问题,尤其是在涉及到AOP代理时

二级缓存earlySingletonObjects用于存储半成品的Bean实例,即那些已经被实例化但尚未完成初始化(如属性填充和方法调用)的Bean。这个缓存允许Spring在Bean的创建过程中就能提前暴露出来,以便于解决循环依赖的问题。然而,如果只有二级缓存,当涉及到AOP代理时,问题就来了。

AOP代理的生成是在Bean的初始化阶段完成的,这意味着在Bean的所有属性都被设置之后。如果一个Bean需要被代理,那么在代理之前,Spring会尽量从缓存中获取到原始的Bean实例,以避免在代理过程中出现循环引用的问题。但是,如果只有二级缓存,那么在Bean初始化之前,我们无法从缓存中获取到代理对象,因为二级缓存中存储的是尚未初始化的Bean实例,而不是代理对象。

举个例子,假设有两个Bean,A和B,它们相互依赖,并且A需要被AOP代理。在Spring的创建过程中,首先会创建A的实例并将其放入二级缓存中。然后,当尝试创建B并注入A时,会发现A还没有完成初始化,因此无法生成A的代理对象。这样就会导致循环依赖的问题无法被解决。

而三级缓存中的singletonFactories存储的是Bean的工厂对象,可以在Bean初始化之前就生成代理对象,并将其放入一级缓存singletonObjects中。这样,即使Bean之间存在循环依赖,Spring也能够通过三级缓存机制成功地创建它们,解决了循环依赖的问题。

总的来说,三级缓存机制是Spring为了在保持设计原则的同时,解决循环依赖和AOP代理的问题而设计的。二级缓存虽然可以解决部分循环依赖的问题,但在面对AOP代理时就显得力不从心了。因此,Spring需要三级缓存来确保在复杂情况下依然能够正常工作。

让我们通过一个具体的例子来理解为什么仅有二级缓存无法解决涉及AOP代理的循环依赖问题。

假设我们有两个Bean,ServiceAServiceB,它们相互依赖,并且ServiceA需要被AOP代理(例如,为了实现事务管理)。

  1. 创建ServiceA实例:Spring首先尝试创建ServiceA的实例。在实例化过程中,ServiceA尚未完成初始化(例如,还未填充属性,未调用初始化方法等),但它的半成品实例被放入了二级缓存earlySingletonObjects

  2. 创建ServiceB实例:接着,Spring尝试创建ServiceB的实例,并试图注入ServiceA。由于ServiceA的完整初始化尚未完成,因此无法生成其AOP代理。

  3. AOP代理问题:在Spring中,AOP代理是在Bean的初始化阶段完成的,这意味着所有的属性填充和方法调用之后。如果ServiceA需要被代理,那么在代理之前,Spring会尝试从缓存中获取到原始的ServiceA实例,以避免在代理过程中出现循环引用的问题。但是,如果只有二级缓存,那么在ServiceA初始化之前,我们无法从缓存中获取到代理对象,因为二级缓存中存储的是尚未初始化的ServiceA实例,而不是代理对象。

  4. 循环依赖:由于ServiceB需要注入ServiceA,而ServiceA又需要被AOP代理,这就形成了一个循环依赖。如果没有三级缓存,Spring就无法在ServiceA完全初始化之前创建一个代理实例来解决这个循环依赖。

现在,让我们看看三级缓存是如何解决这个问题的:

  • 三级缓存singletonFactories:在创建ServiceA的过程中,它的工厂对象会被放入三级缓存singletonFactories。这个工厂对象负责生成ServiceA的实例。

  • 解决循环依赖:当创建ServiceB并尝试注入ServiceA时,Spring会检查三级缓存中是否存在ServiceA的工厂对象。如果存在,Spring使用该工厂对象来创建ServiceA的代理实例,并将其放入一级缓存singletonObjects中。这样,即使ServiceAServiceB相互依赖,Spring也能够通过三级缓存机制成功地创建它们,解决了循环依赖的问题。

总结来说,二级缓存能够解决一些循环依赖问题,但在涉及AOP代理的情况下,它无法提供一个尚未初始化的Bean的代理实例。三级缓存通过引入工厂对象来提前创建代理实例,从而解决了这个问题。

创建ServiceB实例:接着,Spring 尝试创建 ServiceB 的实例,并试图注入 ServiceA。由于 ServiceA 的完整初始化尚未完成,因此无法生成其 AOP 代理。 这里为什么要生成 ServiceA 的 AOP 代理,是不是 ServiceB 要注入的是 ServiceA 的代理对象

是的,ServiceB要注入的是ServiceA的代理对象。在Spring中,如果一个Bean被AOP代理,那么其他Bean注入的是这个Bean的代理对象,而不是原始的Bean实例。这样做的目的是为了让代理对象能够拦截对原始Bean方法的调用,以便在调用前后执行额外的操作,如日志记录、事务管理等。

在创建ServiceB实例时,如果需要注入ServiceA,而ServiceA尚未完成初始化,就无法生成其AOP代理。这是因为AOP代理是在Bean的初始化阶段完成的,这意味着所有的属性填充和方法调用之后。如果ServiceA需要被代理,那么在代理之前,Spring会尝试从缓存中获取到原始的ServiceA实例,以避免在代理过程中出现循环引用的问题。

因此,生成ServiceA的AOP代理是为了确保在Bean的初始化阶段能够生成代理对象,并将其注入到其他Bean中,从而实现横切关注点的模块化。这样,开发人员可以专注于核心业务逻辑的开发,而不必关心那些横切关注点的实现细节。

三级缓存singletonFactories 既可以创建代理bean也可以创建非代理bean

是的,三级缓存singletonFactories可以用于创建代理bean和非代理bean。

在Spring中,singletonFactories是一个Map类型的缓存,它存储了Bean的工厂对象。这些工厂对象负责生成Bean的实例。当需要创建一个Bean时,Spring会首先检查一级缓存singletonObjects中是否已经存在该Bean的实例。如果不存在,则继续检查二级缓存earlySingletonObjects中是否存在半成品的Bean实例。如果仍然不存在,Spring会从三级缓存singletonFactories中获取到对应Bean的工厂对象,并使用该工厂对象来创建Bean的实例。

对于非代理Bean,singletonFactories中的工厂对象直接创建Bean的实例并将其放入一级缓存singletonObjects中。而对于需要被AOP代理的Bean,singletonFactories中的工厂对象会先创建一个原始的Bean实例,然后通过AOP代理来生成代理对象,并将代理对象放入一级缓存singletonObjects中。

因此,三级缓存singletonFactories既可以创建代理bean,也可以创建非代理bean,根据具体的需求和配置来决定是否需要进行AOP代理。文章来源地址https://www.toymoban.com/news/detail-859021.html

到了这里,关于Spring 的三级缓存机制的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

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

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

相关文章

  • 【Spring】三级缓存

    结合文章:循环依赖 测试代码如下: 执行refresh 方法 执行finishBeanFactoryInitialization 方法 执行preInstantiateSingletons 方法 实际上就是通过 doGetBean ,先进行 bean-a 的初始化 去缓存查看时候有 bean - a 实际上就是通过双重校验锁,去查看一级缓存中是否有 bean-a 并且没有在创建中 ,所

    2024年02月21日
    浏览(83)
  • 三级缓存---解决 Spring 循环依赖

    首先,什么是循环依赖?这个其实好理解,就是两个 Bean 互相依赖,类似下面这样: \\\"\\\"\\\" \\\"\\\"\\\" AService 和 BService 互相依赖: 一般来说,循环依赖有三种不同的形态,上面就是其中一种。 另外两种分别是三者依赖,如下图: 这种循环依赖一般隐藏比较深,不易发觉。 还有自我依

    2024年02月16日
    浏览(44)
  • spring解决循环依赖的三级缓存

    实例化,对应方法:AbstractAutowireCapableBeanFactory中的createBeanInstance方法,简单理解就是new了一个对象。 属性注入,对应方法:AbstractAutowireCapableBeanFactory的populateBean方法,为实例化中new出来的对象填充属性和注入依赖。 初始化,对应方法:AbstractAutowireCapableBeanFactory的initialize

    2024年02月03日
    浏览(40)
  • spring bean的三级缓存原理

    当我们在使用 Spring 框架时,通常会遇到循环依赖、AOP 代理等问题。为了解决这些问题,Spring 引入了三级缓存机制, 即 singletonObjects、earlySingletonObjects 和 singletonFactories 三个缓存。本文将详细介绍 Spring 三级缓存的原理和作用。 在 Spring 框架中,Bean 实例化和依赖注入是非常

    2024年02月04日
    浏览(38)
  • Spring——三级缓存解决循环依赖详解

    就是在Bean生成流程中保存Bean对象三种形态的三个Map集合,如下: 用来解决什么问题? 这个大家应该熟知了,就是循环依赖 什么是循环依赖? 就像下面这样,AService 中注入了BService ,而BService 中又注入了AService ,这就是循环依赖 这几个问题我们结合源码来一起看一下 : 三级

    2024年02月03日
    浏览(38)
  • [Spring] 三级缓存解决循环依赖详解

    注册一个bean对象的过程: Spring扫描class得到BeanDefinition – 根据得到的BeanDefinition去生成bean – 现根据class推断构造方法 – 根据推断出来的构造方法,反射,得到一个对象 – 填充初始对象中的属性(依赖注入) – 如果原始对象种的某个方法被AOP了,那么要根据原始对象生成一

    2024年02月15日
    浏览(40)
  • spring 的循环依赖以及spring为什么要用三级缓存解决循环依赖

            bean的生命周期         这里简单过一下 class -无参构造 -普通对象 -依赖注入(对加了autowire等的属性赋值) -初始化前-初始化 -初始化后(aop) -放入单例池的map(一级缓存) -bean对象 这里提一点单例bean单例bean 其实就是用mapbeanName,Bean对象创建的,多例bean就不

    2024年02月15日
    浏览(53)
  • Spring使用三级缓存解决循环依赖?终于完全弄明白了

    文章阅读前推荐 推荐先去看看源码,源码很短,但是对于我们在脑子里构建一个完整思路很重要。看起来非常简单,只需要双击shift,全局查找文件:AbstractAutowireCapableBeanFactory,找到550行左右的doCreateBean方法,重点看一下580行到600行这20行代码就行,包含了三级缓存、属性注

    2024年03月25日
    浏览(58)
  • Spring 为什么要用三级缓存来解决循环依赖(AOP),二级缓存不行吗

    解决有代理对象的循环依赖不一定要三级缓存,用二级甚至一级也能解决,下面讨论下Spring为什么选择三级缓存这个方案。 Spring最开始是没有三级缓存的,后面版本因为引入了AOP,有了代理对象,又因为存在循环依赖,为了保证依赖注入过程注入的是代理对象,且不完全打破

    2024年04月26日
    浏览(37)
  • Spring FrameWork从入门到NB -三级缓存解决循环依赖内幕 (一)

    循环依赖就是我依赖你、你依赖我,或者A依赖B、B依赖C、C依赖A…组成的错综复杂的依赖关系。 其实各种不同的依赖关系最终从逻辑上都可以演变为:我依赖你、你依赖我。 循环依赖大致可以分为两种情况: 属性依赖:比如A对象有一个属性B,B对象有属性A。 构造器依赖:

    2024年02月11日
    浏览(47)

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

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

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

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

二维码1

领取红包

二维码2

领红包