【Spring】三级缓存

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

结合文章:循环依赖

测试代码如下:

public class A {
    private B b;

    public B getB() {
        return b;
    }

    public void setB(B b) {
        this.b = b;
    }

    public A() {
        System.out.println("---A created success");
    }
}
public class B {
    private A a;

    public A getA() {
        return a;
    }

    public void setA(A a) {
        this.a = a;
    }
    
    public B() {
        System.out.println("---B created success");

    }
}
public class ClientSpringContainer {


    public static void main(String[] args) {
        sampleDemo();
    }


    private static void sampleDemo() {
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        A a = context.getBean("a", A.class);
        B b = context.getBean("b", B.class);
    }
}

执行refresh 方法
【Spring】三级缓存,Spring,源码分析,spring,java
执行finishBeanFactoryInitialization 方法
【Spring】三级缓存,Spring,源码分析,spring,java
执行preInstantiateSingletons 方法
【Spring】三级缓存,Spring,源码分析,spring,java

触发所有未加载的实例a - 开始

【Spring】三级缓存,Spring,源码分析,spring,java

getBean( doGetBean) - 获取单例bean

实际上就是通过 doGetBean ,先进行 bean-a 的初始化

getSingleton() - 获取单例bean

去缓存查看时候有 bean - a
【Spring】三级缓存,Spring,源码分析,spring,java
实际上就是通过双重校验锁,去查看一级缓存中是否有 bean-a 并且没有在创建中 ,所以就返回 null
【Spring】三级缓存,Spring,源码分析,spring,java
由于返回了 null ,则 继续往下走,去创建bean-a实例
【Spring】三级缓存,Spring,源码分析,spring,java由于我们 bean-a 是单例的,所以就执行下面的语句块
【Spring】三级缓存,Spring,源码分析,spring,java
再进入内部,发现返回的其实就是执行的就是传参的 createBean(beanName, mbd, args)
【Spring】三级缓存,Spring,源码分析,spring,java
【Spring】三级缓存,Spring,源码分析,spring,java

createBean(doCreateBean) - 创建bean

【Spring】三级缓存,Spring,源码分析,spring,java

createBeanInstance - 创建并返回bean

先执行的是 createBeanInstance,里面是通过构造函数去创建一个bean实例
【Spring】三级缓存,Spring,源码分析,spring,java

addSingletonFactory -放三级缓存

继续,需要暴露出这个bean-a到 三级缓存中,此时我们是有了bean-a的实例:A@2321
【Spring】三级缓存,Spring,源码分析,spring,java

  1. 往三级缓存中放入 a - lamdba@2337
  2. 删除二级缓存

【Spring】三级缓存,Spring,源码分析,spring,java

populateBean - 属性设值

【Spring】三级缓存,Spring,源码分析,spring,java

  1. 先解析看看bean -a 需要那些属性
  2. 在进行设值

【Spring】三级缓存,Spring,源码分析,spring,java

applyPropertyValues - 设值属性

【Spring】三级缓存,Spring,源码分析,spring,java
resolveValueIfNecessary 实际上调用了 resolveReference
【Spring】三级缓存,Spring,源码分析,spring,java
resolveReference 也是通过beanFactory 中获取bean
【Spring】三级缓存,Spring,源码分析,spring,java


初始化b开始

而由于此时工厂里面没有bean-b,没有进行初始化
实际上是调用了doGetBean,又开始了 实例化 bean-b的过程,getBean
【Spring】三级缓存,Spring,源码分析,spring,java

从缓存中获取b

查看一级缓存中是否存在bean-b,返回null
【Spring】三级缓存,Spring,源码分析,spring,java

创建bean-b实例

相当于重复了createBean
由于我们在前一步返回的是null,所以就去执行else语句块的内容
【Spring】三级缓存,Spring,源码分析,spring,java
【Spring】三级缓存,Spring,源码分析,spring,java
常见的是单例bean,进入方法,执行的是createBean方法
【Spring】三级缓存,Spring,源码分析,spring,java
【Spring】三级缓存,Spring,源码分析,spring,java
【Spring】三级缓存,Spring,源码分析,spring,java
调用了doCreateBean方法
【Spring】三级缓存,Spring,源码分析,spring,java
createBeanInstance , B@2627
【Spring】三级缓存,Spring,源码分析,spring,java

提前暴露bean-b

addSingletonFactory
【Spring】三级缓存,Spring,源码分析,spring,java
三级缓存中放入 b - lambda@2644
【Spring】三级缓存,Spring,源码分析,spring,java
此处我们也可以看到在三级缓存中有两个
【Spring】三级缓存,Spring,源码分析,spring,java

b 属性设值

调用 populateBean
【Spring】三级缓存,Spring,源码分析,spring,java
applyPropertyValues
【Spring】三级缓存,Spring,源码分析,spring,java
这里我们可以看到 b 是需要a的(符合我们 前面的需求:a b 互相引用)
【Spring】三级缓存,Spring,源码分析,spring,java
applyPropertyValues 里面又调用了 resolveValueIfNecessary
【Spring】三级缓存,Spring,源码分析,spring,java
resolveValueIfNecessary 又调用了 resolveReference
【Spring】三级缓存,Spring,源码分析,spring,java
resolveReference 调用了 beanFactory.getBean,getBean又是通过doGetBean去获取
【Spring】三级缓存,Spring,源码分析,spring,java
【Spring】三级缓存,Spring,源码分析,spring,java
【Spring】三级缓存,Spring,源码分析,spring,java
先从一级缓存中去获取bean-a ,返回null
【Spring】三级缓存,Spring,源码分析,spring,java
由于一级缓存中没有且a在创建中,执行if语句块
【Spring】三级缓存,Spring,源码分析,spring,java
查看二级缓存中是否有a,没有,执行if 语句块
【Spring】三级缓存,Spring,源码分析,spring,java
再从三级缓存中去获取a, 这里是能够获取从三级缓存中获取到的点击访问
【Spring】三级缓存,Spring,源码分析,spring,java
【Spring】三级缓存,Spring,源码分析,spring,java

  1. a ,三级缓存中的实例 lambda@2337 对应的 实例 A@2321
  2. 放入二级缓存中去 A@2321,此时就已经把a放入二级缓存里面了
  3. 删除三级缓存的内容
  4. 返回缓存中的实例 A@2321

【Spring】三级缓存,Spring,源码分析,spring,java
由于能够从三级缓存中去获取到半成品a,A@2321
【Spring】三级缓存,Spring,源码分析,spring,java
doGetBean 返回 从三级缓存中获取到的A@2321,所以执行if语句快,发现最后返回的是bean,bean是通过getObjectForBeanInstance 去获取的
【Spring】三级缓存,Spring,源码分析,spring,java
getObjectForBeanInstance,又去调用了 super.getObjectForBeanInstance
【Spring】三级缓存,Spring,源码分析,spring,java
getObjectForBeanInstance 就是返回了 A@2321
【Spring】三级缓存,Spring,源码分析,spring,java
doGetBean 结束了,返回了b需要的属性 a(虽然是半成品 A@2321)
【Spring】三级缓存,Spring,源码分析,spring,java
resolveReference 结束,返回 A@2321
【Spring】三级缓存,Spring,源码分析,spring,java
resolveValueIfNecessary结束,返回 A@2321
【Spring】三级缓存,Spring,源码分析,spring,java
退回到applyPropertyValues
【Spring】三级缓存,Spring,源码分析,spring,java
完成属性b设值a( A@2321)
【Spring】三级缓存,Spring,源码分析,spring,java
此时populateBean
(回顾:此时就完成了b的setter注入a),完成了b初始化
【Spring】三级缓存,Spring,源码分析,spring,java
继续,由于在前面,bean-b进行了提前暴露,执行if语句块,所以我们这次flase(意味不需要提前暴露了)
【Spring】三级缓存,Spring,源码分析,spring,java
执行getSingleton, 由于从一级缓存中获取不到,且b在创建中,执行if语句块
【Spring】三级缓存,Spring,源码分析,spring,java
从二级缓存中获取bean-b(肯定是没有的),下图中可以看到我们在二级缓存中也获取不到bean-b,并且不需要提前暴露了,所以不需要执行if语句块
【Spring】三级缓存,Spring,源码分析,spring,java
所以就直接返回null
【Spring】三级缓存,Spring,源码分析,spring,java
返回B@2627
【Spring】三级缓存,Spring,源码分析,spring,java
此时我们就结束了对createBean ,并返回B@2627
【Spring】三级缓存,Spring,源码分析,spring,java
于是我们就能够从三级缓存中去获取到b了
返回b 的 getSingleton,此时就是 B@2627
【Spring】三级缓存,Spring,源码分析,spring,java

放入一级缓存里面

而且,此时我们这个是新创建的bean ,因此 newSingleton = true,执行addSingleton
【Spring】三级缓存,Spring,源码分析,spring,java

  1. 放入一级缓存 b - B@2627
  2. 移除三级缓存
  3. 移除二级缓存

【Spring】三级缓存,Spring,源码分析,spring,java
getSingleton 结束,获取到了 b实例 B@2627
【Spring】三级缓存,Spring,源码分析,spring,java
doGetBean 结束,返回 b实例 B@2627,也就是这一步结束了完成b的初始化
【Spring】三级缓存,Spring,源码分析,spring,java

初始化b结束

那么,接下来,继续完成a的初始化。
resolveReference 结束,返回 b实例 B@2627
【Spring】三级缓存,Spring,源码分析,spring,java
resolveValueIfNecessary结束,返回 b实例 B@2627
【Spring】三级缓存,Spring,源码分析,spring,java
设值a的属性b
【Spring】三级缓存,Spring,源码分析,spring,java
populateBean 结束,完成属性赋值
【Spring】三级缓存,Spring,源码分析,spring,java


初始化a ,A@2321
【Spring】三级缓存,Spring,源码分析,spring,java
前面我们说过我们已经提前暴露了a到三级缓存池里面放到三级缓存池
【Spring】三级缓存,Spring,源码分析,spring,java
执行 getSingleton ,由于
一级缓存里面没有a,且a在创建中,所以 执行if语句块
【Spring】三级缓存,Spring,源码分析,spring,java
由于我们在二级缓存里面能够找到a,if语句就不执行了,因为已经完成了对a的放入二级缓存池

【Spring】三级缓存,Spring,源码分析,spring,java

返回二级缓存池中的对象,A@2321
【Spring】三级缓存,Spring,源码分析,spring,java
于是我们就有了早期暴露对象exposedObject,A@2321,doCreateBean结束
【Spring】三级缓存,Spring,源码分析,spring,java
createBean 结束
【Spring】三级缓存,Spring,源码分析,spring,java
doGetBean结束,返回到getSingleton
【Spring】三级缓存,Spring,源码分析,spring,java
由于这是一个新创建的bean,newSingleton = true,执行addSingleton
【Spring】三级缓存,Spring,源码分析,spring,java

addSingleton- 放一级缓存

  1. a 放入一级缓存:a - A@2321
  2. 移除二级缓存
  3. 移除三级缓存

【Spring】三级缓存,Spring,源码分析,spring,java
getSingleton 结束
【Spring】三级缓存,Spring,源码分析,spring,java
doGetBean 结束
【Spring】三级缓存,Spring,源码分析,spring,java

触发所有未加载的实例a - 结束

【Spring】三级缓存,Spring,源码分析,spring,java

触发所有未加载的实例b - 开始

【Spring】三级缓存,Spring,源码分析,spring,java
【Spring】三级缓存,Spring,源码分析,spring,java
执行getSingleton
【Spring】三级缓存,Spring,源码分析,spring,java
此时,我们的b已经放入了一级缓存了哦,此处就已经完成了b放入一级缓存池,不执行if语句块,返回B@2627
【Spring】三级缓存,Spring,源码分析,spring,java
而我们getGetBean的返回对象bean,就是getSingleton 返回的对象B@2627
【Spring】三级缓存,Spring,源码分析,spring,java

触发所有未加载的实例b - 结束

【Spring】三级缓存,Spring,源码分析,spring,java


preInstantiateSingletons 后面一个循环的语句块,由于这次我们关注的是“循环依赖”,就不着重分析这块 就直接过了
【Spring】三级缓存,Spring,源码分析,spring,java
finishBeanFactoryInitialization 执行结束
【Spring】三级缓存,Spring,源码分析,spring,java
refresh 执行结束
【Spring】三级缓存,Spring,源码分析,spring,java
ClassPathXmlApplicationContext 执行结束
【Spring】三级缓存,Spring,源码分析,spring,java


断点数量如下:
【Spring】三级缓存,Spring,源码分析,spring,java


流程示例图
【Spring】三级缓存,Spring,源码分析,spring,java文章来源地址https://www.toymoban.com/news/detail-832582.html

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

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

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

相关文章

  • Spring三级缓存详解

    Spring三级缓存 是为了解决 对象间的循环依赖 问题。 A依赖B,B依赖A,这就是一个简单的循环依赖。 我们来先看看三级缓存的源码。 (1)查看“获取Bean”的源码,注意getSingleton()方法。 (2)“添加到第1级缓存”的源码: (3)“添加到第3级缓存”的源码: (4)“创建Be

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

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

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

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

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

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

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

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

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

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

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

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

    2024年02月15日
    浏览(57)
  • SpringBoot 三级缓存解决循环依赖源码分析

    在 SpringBoot 框架中,如果只存在两级缓存,那么当发生循环依赖的时候可能存在异常的对象创建流程如下图所示: 创建 A 的空白对象 a1 解析填充 A 对象的属性,发现依赖的 B 对象未创建,则触发 B 对象创建 创建 B 对象过程中,填充对象属性时发现依赖 A 对象,此时从缓存中

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

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

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

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

    2024年04月26日
    浏览(39)

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

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

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

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

二维码1

领取红包

二维码2

领红包