spring ioc的循环依赖问题 什么是循环依赖 spring中循环依赖的场景 通过构造函数注入时的循环依赖 通过setter或@Autowired注入时的循环依赖 循环依赖的处理机制 原型bean循环依赖 单例bean通过构造函数注入循环依赖 单例bean通过setter或者@Autowired注入的循环依赖 回顾bean的创建流程如何处理循环依赖 AbstractBeanFactory#doGetBean AbstractAutowireCapableBeanFactory#createBean(String, RootBeanDefinition, Object[]) AbstractAutowireCapableBeanFactory#doCreateBean DefaultSingletonBeanRegistry#addSingletonFactory AbstractAutowireCapableBeanFactory#populateBean AbstractAutowireCapableBeanFactory#applyPropertyValues BeanDefinitionValueResolver#resolveValueIfNecessary BeanDefinitionValueResolver#resolveReference AbstractBeanFactory#getBean(java.lang.String) AbstractBeanFactory#doGetBean DefaultSingletonBeanRegistry#getSingleton(java.lang.String) DefaultSingletonBeanRegistry#getSingleton(java.lang.String, boolean)
什么是循环依赖
spring ioc的循环依赖通常是指bean与bean之间的相互依赖, 例如A持有对B的引用、B持有对A的引用,形成一个闭环,
相对于这种我们一眼可以看出来的相互引用, 实际引用中可能比这复杂、也隐蔽的多, 要隐蔽、复杂的多, 形成一个环形依赖。
spring中循环依赖的场景
通过构造函数注入时的循环依赖
通过setter或@Autowired注入时的循环依赖
其中,构造函数注入的循环依赖无法解决,只能抛出BeanCurrentlyCreationException异常, 在解决循环依赖时,spring采用的是提前暴露对象的方法。
spring的循环依赖基于Java的引用传递, 当获得对象的引用时,对象属性可以延后设置, 而通过构造器注入时,对象属性则必须在引用之前设置。
setter或@Autowired相当于是获得对象的引用。
循环依赖的处理机制
我们先来回顾一下bean的作用范围, singleton:单例,spring默认的scope,容器中只存在一个对象; prototype:原型,每次getBean都会返回一个新的对象;
单例模式bean的生命周期与容器相同, 原型模式bean,spring框架只负责创建,并不负责销毁。
原型bean循环依赖
无法解决, 对于原型模式的bean初始化过程中, 无论是通过构造器还是属性注入产生的循环依赖,spring都直接会抛出异常。
单例bean通过构造函数注入循环依赖
无法解决。
单例bean通过setter或者@Autowired注入的循环依赖
可以解决,
spring是通过三级缓存来解决循环依赖问题的。
三级缓存
一级缓存:单例池; 二级缓存:earlySingletonObjects; 三级缓存:singletonFactories。
对象的创建分为两步
1、实例化bean; 2、设置属性值。
循环依赖的处理机制
A和B互相依赖,
假如先去创建A, A实例化后先把自己放入三级缓存,目的是为了提前暴露, 然后发现依赖B, 接着创建B,B依赖A, B会去三级缓存中找A,使用并将A放入二级缓存, B创建完后会把自己放入一级缓存, A使用一级缓存中的B。
回顾bean的创建流程如何处理循环依赖
AbstractBeanFactory#doGetBean
这里,
sharedInstance = getSingleton(beanName, () -> {try {return createBean(beanName, mbd, args);}catch (BeansException ex) {// Explicitly remove instance from singleton cache: It might have been put there// eagerly by the creation process, to allow for circular reference resolution.// Also remove any beans that received a temporary reference to the bean.destroySingleton(beanName);throw ex;}});
的lambda表达式就相当于传入了一个方法,
另外getSingleton会将最后创建好的对象放入单例池。
AbstractAutowireCapableBeanFactory#createBean(String, RootBeanDefinition, Object[])
AbstractAutowireCapableBeanFactory#doCreateBean
DefaultSingletonBeanRegistry#addSingletonFactory
放入三级缓存
AbstractAutowireCapableBeanFactory#populateBean
填充属性
AbstractAutowireCapableBeanFactory#applyPropertyValues
BeanDefinitionValueResolver#resolveValueIfNecessary
BeanDefinitionValueResolver#resolveReference
接下来这是获取依赖
AbstractBeanFactory#getBean(java.lang.String)
AbstractBeanFactory#doGetBean
DefaultSingletonBeanRegistry#getSingleton(java.lang.String)
DefaultSingletonBeanRegistry#getSingleton(java.lang.String, boolean)