Spring的三级缓存,伴随着bean的生命周期。
常见缓存
在DefaultSingletonBeanRegistry类中,有很多的cache。
public class DefaultSingletonBeanRegistry extends SimpleAliasRegistry implements SingletonBeanRegistry {
// 一级缓存
/** Cache of singleton objects: bean name to bean instance. */
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);
// 二级缓存
/** Cache of singleton factories: bean name to ObjectFactory. */
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);
// 三级缓存
/** Cache of early singleton objects: bean name to bean instance. */
private final Map<String, Object> earlySingletonObjects = new HashMap<>(16);
/** Set of registered singletons, containing the bean names in registration order. */
private final Set<String> registeredSingletons = new LinkedHashSet<>(256);
// 创建中的beanName的集合
/** Names of beans that are currently in creation. */
private final Set<String> singletonsCurrentlyInCreation =
Collections.newSetFromMap(new ConcurrentHashMap<>(16));
// Bean被创建完成后,会标记为这个
/** Names of beans that have already been created at least once. */
private final Set<String> alreadyCreated = Collections.newSetFromMap(new ConcurrentHashMap<>(256));
}
doGetBean(…)
之前,我们在将Bean的生命周期时,讲到Bean的生命周期是从如下代码开始的
protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,
@Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {
...
// Create bean instance.
// bean的生命周期,从这里正式开始
if (mbd.isSingleton()) {
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;
}
});
bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}
...
}
getSingleton(…)
一、二、三级缓存的操作顺序如下:
在getSingleton(…)方法中,主要进行以下3件事情,从这个方法开始,也进行多个缓存的操作:
public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
...
beforeSingletonCreation(beanName); // 00 bean标记为创建中
try {
singletonObject = singletonFactory.getObject(); // 01 执行createBean -> doCreateBean
newSingleton = true;
}
catch (IllegalStateException ex) {
...
}
finally {
if (recordSuppressedExceptions) {
this.suppressedExceptions = null;
}
afterSingletonCreation(beanName); // 02 bean创建完成,从singletonsCurrentlyInCreation中移除
}
if (newSingleton) {
addSingleton(beanName, singletonObject);
}
...
}
三级缓存加入,二级缓存移除
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)
throws BeanCreationException {
...
// Eagerly cache singletons to be able to resolve circular references
// even when triggered by lifecycle interfaces like BeanFactoryAware.
// 是否需要提前曝光:单例 & 允许循环依赖 & 当前bean正在创建中
boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
isSingletonCurrentlyInCreation(beanName));
if (earlySingletonExposure) {
...
// 加入三级缓存:为避免后期循环依赖,可以在bean初始化完成前将创建实例的ObjectFactory加入工厂
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
}
...
}
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);
}
}
}
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)
throws BeanCreationException {
...
if (earlySingletonExposure) {
Object earlySingletonReference = getSingleton(beanName, false);
}
...
}
二级缓存加入,三级缓存移除
看getSingleton(…)方法,前面加入三级缓存后,这里会将对象从三级缓存移动到二级缓存
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;
}
一级缓存加入,二三级缓存移除
待整个doCreate(…)方法执行完,便再次回到了开头讲的getSingleton(…)方法,在这个方法中,有这么一段代码代码
public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
...
if (newSingleton) {
addSingleton(beanName, singletonObject);
}
...
}
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);
}
}
也就是说,在bean创建完成后(实例化、初始化完成后),最终会放入singletonObjects一级缓存。
总结
现在我们以例子来总结下,Spring借助三级缓存来解决循环依赖的过程
A --> B --> A
- doCreate(…)创建A对象(已实例化,未初始化)
- 将A放入三级缓存singletonFactories
- 调用populateBean(…)方法,A需要注入B,发现缓存里还没有B对象,开始创建B。
- doCreate(…)创建B对象(已实例化,未初始化)
- B对象需要注入A对象,此时从三级缓存取得A对象,同时从三级缓存移动到二级缓存
- B对象继续注入其他属性和初始化,之后将成品B对象放入一级缓存,同时删除二三级缓存。
- A对象获取单例B的引用完成属性注入
- A对象继续注入其他属性和初始化,之后将成品A对象放入一级缓存,同时删除二三级缓存。
Spring三级缓存不能解决的循环依赖问题
多例Bean循环依赖
单例Bean无法注入该多例Bean(非抽象、单例 并且非懒加载的类才能被提前初始bean)
构造器注入依赖
由于Bean的实例化需要构造器,而构造器执行又需要依赖的Bean,所以无法对Bean进行实例化,也就无法使用缓存机制从而报循环依赖错误
可使用@Lazy注解解决
单例注入代理对象依赖
由于代理对象和实际对象是两个对象,所以在生成完毕后Spring会将对象和二级缓存中对象比较,如果不一致则报循环依赖错误
DependsOn循环依赖
当Spring进行加载时,发现有@DependsOn依赖则会直接报错
有个视频不错:
spring为什么使用三级缓存而不是两级? - 李小奔的回答 - 知乎
https://www.zhihu.com/question/445446018/answer/2043081423