一. Bean的生命周期
二. 什么是什么是三级缓存
/** 1级缓存 Cache of singleton objects: bean name to bean instance. */
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);
/** 2级缓存 Cache of early singleton objects: bean name to bean instance. */
private final Map<String, Object> earlySingletonObjects = new HashMap<>(16);
/** 3级缓存 Cache of singleton factories: bean name to ObjectFactory. */
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);
获取单例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) {
singletonObject = singletonFactory.getObject();
this.earlySingletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName);
}
}
}
}
return singletonObject;
}
第一步:第一层缓存singletonObjects 中,获取单例bean,拿到了直接使用,没有拿到则拿二级缓存;
第二步:在二级缓存earlySingletonObjects中,提前暴露的Bean;
第三步:在三级缓存中查找对应的工厂对象,利用拿到的工厂对象去获取包装后的bean。
使用两个map的意义在于将成本对象和半成品对象进行区分,半成品对象是不能直接暴露给外部对象使用的;
三. 为什么用三级缓存不用两级缓存
初始spring是没有解决循环引用问题的,设计原则是 bean 实例化、属性设置、初始化之后 再 生成aop对象,但是为了解决循环依赖但又尽量不打破这个设计原则的情况下,使用了存储了函数式接口的第三级缓存;
如果使用二级缓存的话,可以将aop的代理工作提前到 提前暴露实例的阶段执行; 也就是说所有的bean在创建过程中就先生成代理对象再初始化和其他工作; 但是这样的话,就和spring的aop的设计原则相驳,aop的实现需要与bean的正常生命周期的创建分离; 这样只有使用第三级缓存封装一个函数式接口对象到缓存中, 发生循环依赖时,触发代理类的生成。