Spring循环依赖解决方案

循环依赖bean的创建过程

假设需要创建两个bean,ab,并出现循环依赖。这里ab都应是单例的,注入方式为setter注入

@Component
public class A {
    @Autowired
    private B b;
}
@Component
public class B {
    @Autowired
    private A a;
}

假设Spring容器需要先创建a,则将会执行下列流程

  1. 依次检查一级缓存singletonObjects、二级缓存earlySingletonObjects、三级缓存singletonFactories。由于是第一次获取a,无法从缓存直接返回
  2. 实例化a对象
  3. 将可以获取a对象的单例工厂放进三级缓存singletonFactories
  4. 设置a对象的属性,此时发现需要依赖b,则转向获取b
  5. 依次检查缓存,由于是第一次获取b,无法从缓存直接返回
  6. 实例化b对象
  7. 将可以获取b对象的单例工厂放进三级缓存singletonFactories
  8. 设置b对象的属性,此时发现需要依赖a,则转向获取a
  9. 依次检查缓存,在三级缓存中发现并获取a。在三级缓存获取a的时候,假如有对bean进行AOP处理,会在此时处理并返回一个代理对象,否则返回a本身。在返回之前,会把这个返回的对象加入到二级缓存earlySingletonObjects中,同时把相应的三级缓存删除。
  10. a设置到b对象的属性中
  11. 继续b对象后续的创建过程,完整创建完b对象后,b对象将进入一级缓存singletonObjects,并删除相应的三级缓存。且返回给a对象设置属性使用
  12. b设置到a对象的属性中
  13. 继续a对象后续的创建过程,a存在于二级缓存,二级缓存中可能是已经进行AOP处理的代理对象,需要将这个代理对象放进一级缓存中,然后清除二级缓存

处理循环依赖的一些细节

  1. 非单例的bean无法解决循环依赖
  2. 构造器注入方式可能导致无法解决循环依赖,先创建的bean不能以构造器方式注入后创建的bean。先创建的bean还没放进三级缓存,就需要获取依赖的bean,导致创建过程死循环
  3. 常规的AOP处理在BeanPostProcessorpostProcessAfterInitialization阶段。一般为AbstractAutoProxyCreatorpostProcessAfterInitialization方法。只有在循环依赖出现的时候,才需要把AOP处理提前到从三级缓存取出的时候
  4. 二级缓存和三级缓存的设计是为了解决循环依赖的问题
  5. 三级缓存并不能提高性能,主要还是为了保持Spring原有的设计,在没有循环依赖的情况下,将AOP处理保留在BeanPostProcessorpostProcessAfterInitialization阶段