小工具知识网

当前位置: 首页 > 行业知识 > 【Spring】三级缓存

行业知识

【Spring】三级缓存

2026-11-15 08:03:48 来源:互联网转载

目录标题

  • 触发所有未加载的实例a - 开始
  • getBean( doGetBean) - 获取单例bean
    • getSingleton() - 获取单例bean
    • createBean(doCreateBean) - 创建bean
      • createBeanInstance - 创建并返回bean
      • addSingletonFactory -放三级缓存
      • populateBean - 属性设值
        • applyPropertyValues - 设值属性
          • 初始化b开始
            • 从缓存中获取b
            • 创建bean-b实例
            • 提前暴露bean-b
            • b 属性设值
            • 放入一级缓存里面
            • 初始化b结束
            • image.png
            • addSingleton- 放一级缓存
            • 触发所有未加载的实例a - 结束
            • 触发所有未加载的实例b - 开始
            • 触发���有未加载的实例b - 结束

              结合文章:循环依赖

              测试代码如下:

              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 方法

              执行finishBeanFactoryInitialization 方法

              执行preInstantiateSingletons 方法

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

              getBean( doGetBean) - 获取单例bean

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

              getSingleton() - 获取单例bean

              去缓存查看时候有 bean - a

              实际上就是通过双重校验锁,去查看一级缓存中是否有 bean-a 并且没有在创建中 ,所以就返回 null

              由于返回了 null ,则 继续往下走,去创建bean-a实例
              由于我们 bean-a 是单例的,所以就执行下面的语句块

              再进入内部,发现返回的其实就是执行的就是传参的 createBean(beanName, mbd, args)

              createBean(doCreateBean) - 创建bean

              createBeanInstance - 创建并返回bean

              先执行的是 createBeanInstance,里面是通过构造函数去创建一个bean实例

              addSingletonFactory -放三级缓存

              继续,需要暴露出这个bean-a到 三级缓存中,此时我们是有了bean-a的实例:A@2321

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

              populateBean - 属性设值

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

              初始化b开始

              而由于此时工厂里面没有bean-b,没有进行初始化
              实际上是调用了doGetBean,又开始了 实例化 bean-b的过程,getBean

              从缓存中获取b

              查看一级缓存中是否存在bean-b,返回null

              创建bean-b实例

              相当于重复了createBean
              由于我们在前一步返回的是null,所以就去执行else语句块的内容


              常见的是单例bean,进入方法,执行的是createBean方法



              调用了doCreateBean方法

              createBeanInstance , B@2627

              提前暴露bean-b

              addSingletonFactory

              三级缓存中放入 b - lambda@2644

              此处我们也可以看到在三级缓存中有两个

              b 属性设值

              调用 populateBean

              applyPropertyValues

              这里我们可以看到 b 是需要a的(符合我们 前面的需求:a b 互相引用)

              applyPropertyValues 里面又调用了 resolveValueIfNecessary

              resolveValueIfNecessary 又调用了 resolveReference

              resolveReference 调用了 beanFactory.getBean,getBean又是通过doGetBean去获取



              先从一级缓存中去获取bean-a ,返回null

              由于一级缓存中没有且a在创建中,执行if语句块

              查看二级缓存中是否有a,没有,执行if 语句块

              再从三级缓存中去获取a, 这里是能够获取从三级缓存中获取到的点击访问

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

              而且,此时我们这个是新创建的bean ,因此 newSingleton = true,执行addSingleton

              1. 放入一级缓存 b - B@2627
              2. 移除三级缓存
              3. 移除二级缓存
              初始化b结束

              那么,接下来,继续完成a的初始化。
              resolveReference 结束,返回 b实例 B@2627

              resolveValueIfNecessary结束,返回 b实例 B@2627

              设值a的属性b

              populateBean 结束,完成属性赋值


              初始化a ,A@2321

              前面我们说过我们已经提前暴露了a到三级缓存池里面放到三级缓存池

              执行 getSingleton ,由于
              一级缓存里面没有a,且a在创建中,所以 执行if语句块

              由于我们在二级缓存里面能够找到a,if语句就不执行了,因为已经完成了对a的放入二级缓存池

              返回二级缓存池中的对象,A@2321

              于是我们就有了早期暴露对象exposedObject,A@2321,doCreateBean结束

              createBean 结束

              doGetBean结束,返回到getSingleton

              由于这是一个新创建的bean,newSingleton = true,执行addSingleton

              addSingleton- 放一级缓存

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

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

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

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


              preInstantiateSingletons 后面一个循环的语句块,由于这次我们关注的是“循环依赖”,就不着重分析这块 就直接过了

              finishBeanFactoryInitialization 执行结束

              refresh 执行结束

              ClassPathXmlApplicationContext 执行结束


              断点数量如下:


              流程示例图

              纠错:

              1. 标题为 :初始化a 初始化b
              2. 结尾:a初始化结束 b初始化结束

上一篇:新昌服务器在哪里买?

下一篇:Java实现分片上传(前端分,后端合并)