Spring三级缓存解决循环依赖( 二 )


  1. 实例化对象
  2. 对象填充属性
  3. BeanPostProcessor doBefore
  4. init-method
  5. BeanPostProcessor doAfter -- AOP是在这个阶段实现的
所以要实现上面的方案 , 势必需要将BeanPostProcessor阶段提前或者侵入到填充属性的流程中 , 那么从程序设计上来说 , 这样做肯定是不美的 。
三级缓存Spring引入了第三级缓存来解决这个问题 ,  Map3 {k:name v:ObjectFactory}  , 这个缓存的value就不是Bean对象了 , 而是一个接口对象由一段lamda表达式实现 。在这段lamda表达式中去完成一些BeanPostProcessor的执行 。
  1. 实例化A对象之后 , 将A的ObjectFactory对象放入Map3中 。
  2. 在填充A的属性阶段需要去填充B对象 , 而此时B对象还没有创建 , 所以这里为了完成A的填充就必须要先去创建B对象 。
  3. 创建B对象的过程中 , 实例化B的ObjectFactory对象之后 , 将B对象放入Map2中 。
  4. 执行到B对象填充属性阶段 , 又会需要去获取A对象 , 而此时Map1中没有A , 因为A还没有创建完成 , 但是我们继续从Map2中也拿不到 , 到Map3中获取了A的ObjectFactory对象 , 通过ObjectFactory对象获取A的早期对象 , 并将这个早期对象放入Map2中 , 同时删除Map3中的A , 将尚未创建完毕的A的引用赋值给a字段 。这样B对象其实就已经创建完整了 , 尽管B.a对象是一个还未创建完成的对象 。
  5. 此时将B放入Map并且从Map3中删除 。
  6. 这时候B创建完成 , A继续执行b的属性填充可以拿到B对象 , 这样A也完成了创建 。
  7. 此时将A对象放入Map并从Map2中删除 。

Spring三级缓存解决循环依赖

文章插图
取自别人家的图
源码步骤解析
  1. SpringBoot项目启动执行到SpringApplication#run 中的refreshContext(context); , 最终调用Spring容器的AbstractApplicationContext#refresh方法 , 开始初始化BeanFactory 。
  2. 在AbstractApplicationContext#refresh步骤中 , 执行到AbstractApplicationContext#finishBeanFactoryInitialization方法 , 开始完成 Bean 工厂初始化 。
  3. 执行到AbstracBeanFactory.preInstantiateSingletons() , 开始根据BeanFactory中的BeanDefinition信息初始化Bean对象 。
  4. 在AbstracBeanFactory.preInstantiateSingletons()方法中 , 发现A对象的BeanDefinition , 执行AbstracBeanFactory.getBean方法 , 获取A对象 。
  5. 在AbstracBeanFactory.getBean方法中 , 执行AbstracBeanFactory.doGetBean方法 , 获取A对象 。
  6. 在AbstracBeanFactory.doGetBean方法中执行DefaultSingletonBeanRegistry#getSingleton方法 , 尝试从缓存中获取A对象的单例对象缓存 。到一级缓存singletonObjects中找 , 未找到; 到二级缓存earlySingletonObjects中找 , 未找到; 到三级缓存singletonFactories中找 , 未找到;
  7. 再次执行DefaultSingletonBeanRegistry#getSingleton的重载方法 , 传入lamda表达式形式的ObjectFactory对象 , 内部调用AbstractAutowireCapableBeanFactory#createBean方法 , 尝试创建A对象 。
  8. 在AbstractAutowireCapableBeanFactory#createBean方法中 , 调用AbstractAutowireCapableBeanFactory#doCreateBean方法 , 实际执行创建A对象 。
  9. 实例化A对象 , 给字段赋值默认值后 , 调用DefaultSingletonBeanRegistry#addSingletonFactory方法 , 传入A对象的lamda表达式形式的ObjectFactory对象 , 将ObjectFactory对象放入三级缓存singletonFactories中 , 并从2级缓存earlySingletonObjects中移除(虽然这里没有) , 设置A对象已经开始注册 。此处传入的lamda表达式 , 内部调用了AbstractAutowireCapableBeanFactory#getEarlyBeanReference , 此方法用来执行实现了SmartInstantiationAwareBeanPostProcessor的后置处理器 , 比如实现AOP的AbstractAutoProxyCreator
  10. 然后开始执行A对象的AbstractAutowireCapableBeanFactory#populateBean , 进行属性填充 。
  11. 在进行属性填充时 , 发现依赖了B对象 , 执行AbstracBeanFactory.getBean方法 , 尝试获取B对象 。参考上面步骤4~9 。


    推荐阅读