【Spring】三级缓存
作者:mmseoamin日期:2024-02-28

目录标题

  • 触发所有未加载的实例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 方法
              【Spring】三级缓存,image.png,第1张
              执行finishBeanFactoryInitialization 方法
              【Spring】三级缓存,image.png,第2张
              执行preInstantiateSingletons 方法
              【Spring】三级缓存,image.png,第3张

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

              【Spring】三级缓存,image.png,第4张

              getBean( doGetBean) - 获取单例bean

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

              getSingleton() - 获取单例bean

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

              createBean(doCreateBean) - 创建bean

              【Spring】三级缓存,image.png,第11张

              createBeanInstance - 创建并返回bean

              先执行的是 createBeanInstance,里面是通过构造函数去创建一个bean实例
              【Spring】三级缓存,image.png,第12张

              addSingletonFactory -放三级缓存

              继续,需要暴露出这个bean-a到 三级缓存中,此时我们是有了bean-a的实例:A@2321
              【Spring】三级缓存,image.png,第13张

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

              【Spring】三级缓存,image.png,第14张

              populateBean - 属性设值

              【Spring】三级缓存,image.png,第15张

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

              【Spring】三级缓存,image.png,第16张

              applyPropertyValues - 设值属性

              【Spring】三级缓存,image.png,第17张
              resolveValueIfNecessary 实际上调用了 resolveReference
              【Spring】三级缓存,image.png,第18张
              resolveReference 也是通过beanFactory 中获取bean
              【Spring】三级缓存,image.png,第19张


              初始化b开始

              而由于此时工厂里面没有bean-b,没有进行初始化
              实际上是调用了doGetBean,又开始了 实例化 bean-b的过程,getBean
              【Spring】三级缓存,image.png,第20张

              从缓存中获取b

              查看一级缓存中是否存在bean-b,返回null
              【Spring】三级缓存,image.png,第21张

              创建bean-b实例

              相当于重复了createBean
              由于我们在前一步返回的是null,所以就去执行else语句块的内容
              【Spring】三级缓存,image.png,第22张
              【Spring】三级缓存,image.png,第23张
              常见的是单例bean,进入方法,执行的是createBean方法
              【Spring】三级缓存,image.png,第24张
              【Spring】三级缓存,image.png,第25张
              【Spring】三级缓存,image.png,第26张
              调用了doCreateBean方法
              【Spring】三级缓存,image.png,第27张
              createBeanInstance , B@2627
              【Spring】三级缓存,image.png,第28张

              提前暴露bean-b

              addSingletonFactory
              【Spring】三级缓存,image.png,第29张
              三级缓存中放入 b - lambda@2644
              【Spring】三级缓存,image.png,第30张
              此处我们也可以看到在三级缓存中有两个
              【Spring】三级缓存,image.png,第31张

              b 属性设值

              调用 populateBean
              【Spring】三级缓存,image.png,第32张

              applyPropertyValues
              【Spring】三级缓存,image.png,第33张
              这里我们可以看到 b 是需要a的(符合我们 前面的需求:a b 互相引用)
              【Spring】三级缓存,image.png,第34张
              applyPropertyValues 里面又调用了 resolveValueIfNecessary
              【Spring】三级缓存,image.png,第35张
              resolveValueIfNecessary 又调用了 resolveReference
              【Spring】三级缓存,image.png,第36张
              resolveReference 调用了 beanFactory.getBean,getBean又是通过doGetBean去获取
              【Spring】三级缓存,image.png,第37张
              【Spring】三级缓存,image.png,第38张
              【Spring】三级缓存,image.png,第39张
              先从一级缓存中去获取bean-a ,返回null
              【Spring】三级缓存,image.png,第40张
              由于一级缓存中没有且a在创建中,执行if语句块
              【Spring】三级缓存,image.png,第41张
              查看二级缓存中是否有a,没有,执行if 语句块
              【Spring】三级缓存,image.png,第42张
              再从三级缓存中去获取a, 这里是能够获取从三级缓存中获取到的点击访问
              【Spring】三级缓存,image.png,第43张
              【Spring】三级缓存,image.png,第44张

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

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

              放入一级缓存里面

              而且,此时我们这个是新创建的bean ,因此 newSingleton = true,执行addSingleton
              【Spring】三级缓存,image.png,第63张

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

              【Spring】三级缓存,image.png,第64张
              getSingleton 结束,获取到了 b实例 B@2627
              【Spring】三级缓存,image.png,第65张
              doGetBean 结束,返回 b实例 B@2627,也就是这一步结束了完成b的初始化
              【Spring】三级缓存,image.png,第66张

              初始化b结束

              那么,接下来,继续完成a的初始化。
              resolveReference 结束,返回 b实例 B@2627
              【Spring】三级缓存,image.png,第67张
              resolveValueIfNecessary结束,返回 b实例 B@2627
              【Spring】三级缓存,image.png,第68张
              设值a的属性b
              【Spring】三级缓存,image.png,第69张
              populateBean 结束,完成属性赋值
              【Spring】三级缓存,image.png,第70张


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

              【Spring】三级缓存,image.png,第74张

              返回二级缓存池中的对象,A@2321
              【Spring】三级缓存,image.png,第75张
              于是我们就有了早期暴露对象exposedObject,A@2321,doCreateBean结束
              【Spring】三级缓存,image.png,第76张
              createBean 结束
              【Spring】三级缓存,image.png,第77张
              doGetBean结束,返回到getSingleton
              【Spring】三级缓存,image.png,第78张
              由于这是一个新创建的bean,newSingleton = true,执行addSingleton
              【Spring】三级缓存,image.png,第79张

              addSingleton- 放一级缓存

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

              【Spring】三级缓存,image.png,第80张
              getSingleton 结束
              【Spring】三级缓存,image.png,第81张
              doGetBean 结束
              【Spring】三级缓存,image.png,第82张

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

              【Spring】三级缓存,image.png,第83张

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

              【Spring】三级缓存,image.png,第84张
              【Spring】三级缓存,image.png,第85张
              执行getSingleton
              【Spring】三级缓存,image.png,第86张
              此时,我们的b已经放入了一级缓存了哦,此处就已经完成了b放入一级缓存池,不执行if语句块,返回B@2627
              【Spring】三级缓存,image.png,第87张
              而我们getGetBean的返回对象bean,就是getSingleton 返回的对象B@2627
              【Spring】三级缓存,image.png,第88张

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

              【Spring】三级缓存,image.png,第89张


              preInstantiateSingletons 后面一个循环的语句块,由于这次我们关注的是“循环依赖”,就不着重分析这块 就直接过了
              【Spring】三级缓存,image.png,第90张
              finishBeanFactoryInitialization 执行结束
              【Spring】三级缓存,image.png,第91张
              refresh 执行结束
              【Spring】三级缓存,image.png,第92张
              ClassPathXmlApplicationContext 执行结束
              【Spring】三级缓存,image.png,第93张


              断点数量如下:
              【Spring】三级缓存,image.png,第94张


              流程示例图

              纠错:

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

                【Spring】三级缓存,在这里插入图片描述,第95张