什么是循环依赖
循环依赖是指一个或多个对象之间存在直接或间接的依赖关系,这种依赖关系构成一个循环。
- 自己依赖自己 ( eg:在A类里注入了A)
- 两个对象之间互相依赖(eg:A里注入了B,B里注入了A)
- 多个对象之间相互依赖(eg:A里注入了B,…,X里注入了A)
循环依赖的产生方式
- 构造器注入的循环依赖:直接抛出BeanCurrentlylnCreationException异常。
- 非单例循环依赖:无法处理。
- 单例模式下的属性注入的循环依赖:可通过三级缓存处理
spring框架无法处理构造器及非单例下的循环依赖,可以通过三级缓存处理单例模式下的循环依赖。
spring通过三级缓存处理单例模式下的循环依赖
三级缓存
首先来了解一下三级缓存:
- 一级缓存,singletonObjects :完成了初始化的单例对象map
- 二级缓存,earlySingletonObjects:完成实例化未初始化的单例对象ma
- 三级缓存,singletonFactories: 单例对象工厂map,单例对象实例化完成之后会加入singletonFactories
初始化步骤
- createBeanInstance :实例化bean,使用构造方法创建对象,为对象分配内存。
- populateBean :进行依赖注入。
- initializeBean :初始化bean。
解决
以下引用ximeneschen的spring循环依赖及解决方法
在调用createBeanInstance进行实例化之后,会调用addSingletonFactory,将单例对象放到singletonFactories中。
protected void addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory) {
Assert.notNull(singletonFactory, "Singleton factory must not be null"); synchronized (this.singletonObjects) {
// 判断一级缓存中不存在此对象
if (!this.singletonObjects.containsKey(beanName)) {
// 添加至三级缓存
this.singletonFactories.put(beanName, singletonFactory);
this.earlySingletonObjects.remove(beanName);
this.registeredSingletons.add(beanName);
} } }
Spring 在注入属性的时候是如何去获取依赖的呢?
他是通过一个getSingleton()方法去获取所需要的 Bean 的。
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
// 一级缓存
Object singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
synchronized (this.singletonObjects) {
// 二级缓存
singletonObject = this.earlySingletonObjects.get(beanName);
if (singletonObject == null && allowEarlyReference) {
// 三级缓存
ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
if (singletonFactory != null) {
// Bean 工厂中获取 Bean
singletonObject = singletonFactory.getObject();
// 放入到二级缓存中
this.earlySingletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName);
}
}
}
}
return singletonObject;
}
当 Spring 为某个 Bean 填充属性的时候,它首先会从一级缓存中获取,一级缓存中没有就从二级缓存中获取,二级缓存中没有就从三级缓存中获取,如果三级缓存中也没有,那么就会去执行 doCreateBean() 方法创建这个 Bean。