Spring循环依赖面试问题

循环依赖

  • 循环依赖、循环调用
  • 循环依赖是针对成员变量---单例才可以解决setter方法循环依赖,多例是无法解决循环依赖
    • 构造方法循环依赖----无法解决,只有将构造依赖改为setter方法依赖
    • setter方法循环依赖---可以解决
  • 循环调用是针对方法---无法解决的
  • 结论:
    • 循环调用就是A方法调用B方法,B方法调用A方法,这是一个闭环,是死循环,只能规避,无法解决
  • 解决setter方法循环依赖
    • Spring循环依赖面试问题
  • A对象依赖B对象、B对象依赖A对象
    • A对象创建(实例化)
      • 在1和2之间需要做一个处理:会将刚创建的bean通过ObjectFactory进行暴露,并且将ObjectFactory放入三级缓存
    • A对象属性填充
      • A对象给B对象属性进行赋值,需要获取B对象的值getBean();
        • B对象实例化
        • B对象属性填充
          • B对象给A对象属性进行赋值,需要获取A对象的值getBean();
          • 直接从缓存中取出对应的A对象?
        • B对象初始化
    • A对象初始化
  • getBean流程
    • 先去缓存中获取对应的bean
      • 先去一级缓存查找-----------------------------value:完全初始化完毕的bean实例
      • 没有再去二级缓存查找-----------------------value:只完成bean实例化的bean的实例
      • 没有再去三级缓存查找-----------------------value:ObjectFactory通过该缓存将只完成bean实例化和bean的实例提前暴露(不只是将bean的引用放入缓存中,还需要对该未初始化完成的bean进行一些BeanPostProcessor处理)
    • 如果bean没有再进行创建,并且将创建之后的bean放入缓存中
  • 为什么要有三个缓存?
    • 主要是通过二级缓存和三级缓存在解决循环依赖的问题。其中二级缓存和三级缓存有互斥的
  • 三级缓存和二级缓存的区别?
    • 二级缓存只需要存储beanName和提前暴露的bean的实例的映射关系即可;
    • 三级缓存不仅需要提前暴露的bean进行返回,还要对该bean做BeanPostProcessor后置处理;
    • 三级缓存将暴露的bean处理完之后,将暴露的bean转移到二级缓存,同时删除三级缓存的数据;
    • 三级缓存才是解决循环依赖的根本;
  • 引用是可以传递的,提前暴露的bean和完全初始化成功的bean,其实是一个对象。