spring循环依赖

  1. what
    •   实例化一个完整的bean主要分两步,实例化(调用构造器在堆内存中分配一块内存)和初始化(给属性赋值);
    •   ClassA中有ClassB属性,ClassB中有ClassA属性,导致在bean初始化填充属性时,导致循环依赖
  2. when
    •   在bean生成周期的属性填充阶段(populateBean)
  3. why
    •   ClassA中有ClassB属性,ClassB中有ClassA属性,导致在bean初始化填充属性时,导致循环依赖
  4. how(如何解决)
    •   使用三级缓存,DefaultSingletonBeanRegistry
    •  

    • 缓存 存储的内容 作用 备注

      一级缓存

       

      成品对象
      二级缓存 半成品对象,只做了实例化(在堆内存中分配了空间),未做初始化
      三级缓存 lambda表达式 获取源对象或代理对象
      AbstractAutowireCapableBeanFactory#doGetBean中

      getEarlyBeanReference逻辑(生成代理对象或原对象)

 

  QA:

  q:可以只用一个map集合吗?

  a:可以,但不优雅,需要区分一个实例的半成品和成品,通过在key上加前缀等方案做区分,代码不友好;

  q: 只用两级缓存,可以吗?

  a:如果没有动态代理,可以;

  q:为什么有动态代理就需要第三级缓存?

  a:动态代理的生成在bean生命周期的BeanPostProcessor的postProcessAfterInitialization方法中实现,而bean的属性填充在此之前,所以此时并没有创建出对应的代理对象(如果需要代理对象的话);   所以需要提前生成代理对象,但spring无法感知是否需要生成代理对象(是由业务代码决定的),所以需要的属性填充之前唯一确定是原始对象还是代理对象,而属性的赋值时间也不可控,所有通过lambda表达式类似回调的机制在属性填充时确定是原对象还是代理对象。

posted @ 2023-03-22 22:10  Katsu  阅读(16)  评论(0编辑  收藏  举报