Spring---循环依赖
总结
什么是循环依赖?
A对象中有属性B对象,B对象中有属性A对象;
Spring如何解决循环依赖?
1、将Bean的创建分成 实例化 + 初始化 2个过程;
2、提供了3级缓存维护单例Bean:
- singletonObjects:保存已经初始化完毕的单例Bean。
- earlySingletonObjects:保存已经被实例化但未完全初始化的Bean。 这些Bean是为了解决循环依赖而提前暴露出来的。
- singletonFactories:保存用来生成Bean的ObjectFactory。 当需要提前暴露Bean时,会从这里获取对应的ObjectFactory并调用getObject()方法得到Bean的早期引用。
-
创建Bean实例:
- Spring首先尝试创建一个Bean A的实例。
- 如果发现Bean A依赖于Bean B,那么Spring会暂停A的初始化,并开始创建Bean B。
-
提前暴露早期引用:
- 在创建Bean B的过程中,如果B又依赖于A,Spring会在
singletonFactories中为A创建一个ObjectFactory,并将这个工厂放入singletonFactories缓存。 - 然后Spring从
singletonFactories获取A的ObjectFactory并调用其getObject()方法得到A的一个早期引用(未完全初始化的对象),并将这个早期引用放入earlySingletonObjects缓存。 - 使用A的早期引用继续B的初始化过程。
- 在创建Bean B的过程中,如果B又依赖于A,Spring会在
-
完成依赖注入:
- 当B完成初始化后,它会被放入
singletonObjects缓存。 - 接着,Spring返回到A的初始化过程,完成A的属性注入和其他初始化工作。
- 当B完成初始化后,它会被放入
-
完成Bean A的初始化:
- 一旦A的所有依赖都已注入,并且所有初始化回调(如
@PostConstruct注解的方法或InitializingBean.afterPropertiesSet()等)都执行完毕,A就被认为是完全初始化的。 - 完全初始化后的A从
earlySingletonObjects移除,并被放入singletonObjects缓存,成为完整的单例Bean。
- 一旦A的所有依赖都已注入,并且所有初始化回调(如
当Spring尝试创建一个Bean A时,如果发现A依赖于Bean B,而B又依赖于A,那么Spring会执行以下步骤:
- 创建Bean A的实例,此时A处于创建中状态。
- 尝试创建Bean B的实例,同样B也处于创建中状态。
- 在创建B的过程中,发现它依赖于A,但由于A已经在创建过程中,Spring会从
singletonFactories中获取A的ObjectFactory,然后调用getObject()方法得到A的早期引用。 - 使用A的早期引用完成B的初始化。
- 完成A的初始化,将其放入
singletonObjects中。
3、在Spring中,提供的DI方式中:
- 构造器注入:如果使用构造器注入(constructor injection),Spring将无法解决循环依赖问题,因为每个Bean都需要另一个完全初始化的Bean作为其构造参数。在这种情况下,Spring会抛出
BeanCurrentlyInCreationException。 - Setter注入(属性注入&setter注入):Spring可以使用setter注入(field injection)来解决循环依赖问题。当一个Bean正在被创建但尚未完成时,Spring会提前暴露这个Bean的一个早期引用(early reference)。这样,其他依赖它的Bean就可以获得这个早期引用,并继续它们的初始化过程。
/**
* what?
* A对象中有属性B对象,B对象中有属性A对象;
* 创建任何对象,都是先实例化,后初始化;
*
* 如何解决循环依赖?
* 1、实例化(createBeanInstance) 与 初始化(populateBean,initializeBean) 分开;
* 2、设置缓存预存对象(先将 先实例化的A对象 缓存起来,在B对象初始化设置属性A时,从 缓存中获取A实例,进行赋值);
*
* 使用半成品对象会有问题,如何解决?
* spring3级缓存:org.springframework.beans.factory.support.DefaultSingletonBeanRegistry
*
* 1级缓存:
* private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);
* k:beanName
* v:bean
*
* 2级缓存:
* private final Map<String, Object> earlySingletonObjects = new HashMap<>(16);
* k:beanName
* v:本成品bean
*
* 3级缓存:
* private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);
* k:beanName
* v:lambada表达式
*
*/
浙公网安备 33010602011771号