目录
循环依赖和三级依赖
Spring 三级缓存和循环依赖(紧密相关)
循环依赖
- 指的是两个或多个Bean之间相互依赖,如Bean A依赖于Bean B,而Bean B又依赖于Bean A,则会出现循环依赖的情况
- Spring默认采用Singleton模式,Bean默认是单例的,在容器启动时就会创建Bean实例,同时也会注入它所依赖的Bean实例
- 当出现循环依赖的情况时,Spring的Bean实例化策略就会出现问题
- 大家开发过程中好像对循环依赖这个概念无感知,这种错觉是因为工作在Spring的中,已经帮你解决了
解决方案
- Spring引入了"提前暴露Bean"的机制,在创建A对象时,会先创建一个A的空对象并将其添加到缓存池中
- 即"提前暴露Bean",然后继续创建B对象,将其注入A对象中
- 在创建B对象时,由于A对象已经在缓存池中,可以直接获取到A对象,接着将B对象注入到A对象中,完成Bean的初始化
- 注意:循环依赖的场景
- 单例
- 构造器循环依赖(构造器注入,循环依赖无法解决,日常开发不推荐构造器注入)
- Field属性循环依赖(set方法注入,循环依赖问题可以解决,通过三级缓存)
- 多例
- prototype类型bean(循环依赖无法解决,构造函数和属性注入都不能解决循环依赖)
AbstractBeanFactory#doGetBean
- 单例
缓存说明
- 三级缓存,当Spring创建Bean的过程中,使用3个缓存存储已经创建的Bean实例,Map结构
- 一级缓存(成熟的bean) Singletons object cache
singletonObjects
单例池 ,存储已经创建好的无代理的单例Bean对象,从该缓存中取出的 bean 可以直接使用
- 二级缓存 Early-singletons object cache
earlySingletonObjects
提前曝光的单例对象的cache,存放原始的 bean 对象(尚未填充属性),用于解决循环依
- 三级缓存 Singleton Factory object cache
singletonFactories
单例对象工厂的cache,存放 bean 工厂对象,解决循环依赖 避免Bean的实例化顺序出现问题
- 一级缓存(成熟的bean) Singletons object cache
总结
- Spring的三级缓存机制是为了避免Spring中的循环依赖问题而引入的
- 也可以提高Bean的创建效率,避免创建重复的对象,从而提高应用程序的性能
三级缓存流程解析
Bean的创建流程

循环依赖代码案例
java
@Service
public class OneServiceImpl implements OneService {
@Autowired
private TwoService twoService;
...
}
java
@Service
public class TwoServiceImpl implements TwoService {
@Autowired
private OneService oneService;
...
}
关键类 DefaultSingletonBeanRegistry
bash
/**
* 一级缓存,单例池 ,存储已经创建好的无代理的单例Bean对象,从该缓存中取出的 bean 可以直接使用
* */
Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);
/**
* 三级缓存, 单例对象工厂的cache,存放 bean 工厂对象,解决循环依赖 避免Bean的实例化顺序出现问题。
* */
Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);
/**
* 二级缓存, 提前曝光的单例对象的cache,存放原始的 bean 对象(尚未填充属性),用于解决循环依
* */
Map<String, Object> earlySingletonObjects = new ConcurrentHashMap<>(16);
/** 用于保存已经创建的 Bean 的单例对象,能够确保应用程序上下文中每个单例 Bean 对象最多只创建一次,并且可以保证单例 Bean 的唯一性 */
Set<String> registeredSingletons = new LinkedHashSet<>(256);
/** 表示bean创建过程中都会存储这里,创建完成后会被移除 */
Set<String> singletonsCurrentlyInCreation = Collections.newSetFromMap(new ConcurrentHashMap<>(16));
//add 关键方法
//把创建的bean加到一级缓存中,然后把二级和三级缓存的bean移除
addSingleton(String beanName, Object singletonObject)
//三级缓存中存储,二级缓存中移除bean ,ObjectFactory是函数式接口
addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory)
//get关键方法
//根据bean名称获取对应的bean,如果不存在则创建新的,ObjectFactory是调用外部传递进来的lambda表达式
getSingleton(String beanName, ObjectFactory<?> singletonFactory)
//用于从单例池中获取指定名称的单例 Bean 实例,方法内部实现了三级缓存查找机制
getSingleton(String beanName, boolean allowEarlyReference)
关键类 ObjectFactory
bash
/**
* 将创建对象的步骤封装到ObjectFactory中, 外部通过lambda表达式把相关创建步骤传递进来,返回创建好的对象
/
@FunctionalInterface
public interface ObjectFactory<T> {
T getObject() throws BeansException;
}

循环依赖流程图


java
// 1、bean构建完毕,从singletonsCurrentlyIncreation集合中删除对应的beanName
afterSingletonCreation(beanName);
// 2、添加到单例缓存池中,并从二级缓存和三级缓存中删除
addSingleton(beanName, singletonObject);
java
// 添加到单例缓存池中,并从二级缓存和三级缓存中删除
protected void addSingleton(String beanName, Object singletonObject) {
synchronized (this.singletonObjects) {
this.singletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName);
this.earlySingletonObjects.remove(beanName);
this.registeredSingletons.add(beanName);
}
}
补充-Spring循环依赖异常
