前言
都知道spring解决循环依赖问题是通过三级缓存模式;
之所以把spring初始化缓存分为三级,主要是根据spring源码中获取bean的顺序来分的,spring获取bean的代码如下:
org.springframework.beans.factory.support.DefaultSingletonBeanRegistry
/** Cache of singleton objects: bean name --> bean instance */
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<String, Object>(256);
/** Cache of singleton factories: bean name --> ObjectFactory */
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<String, ObjectFactory<?>>(16);
/** Cache of early singleton objects: bean name --> bean instance */
private final Map<String, Object> earlySingletonObjects = new HashMap<String, Object>(16);
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
// 一级缓存:从singletonObjects中找
Object singletonObject = this.singletonObjects.get(beanName);
// 如果找不到,判断是不是正在创建
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
synchronized (this.singletonObjects) {
// 二级缓存:从earlySingletonObjects中找
singletonObject = this.earlySingletonObjects.get(beanName);
if (singletonObject == null && allowEarlyReference) {
// 三级缓存:从singletonFactories中找
ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
if (singletonFactory != null) {
// 找到后把bean放到earlySingletonObjects中,并从singletonFactories中删除
singletonObject = singletonFactory.getObject();
this.earlySingletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName);
}
}
}
}
return (singletonObject != NULL_OBJECT ? singletonObject : null);
}
- 一级缓存:Map<String, Object> singletonObjects,存储可以用的bean,即:初始化完成的成品bean;
- 二级缓存:Map<String, Object> earlySingletonObjects,存储bean的实例化对象,该对象还没有完全初始化好的半成本;
- 三级缓存:Map<String, ObjectFactory<?>> singletonFactories,存储生成bean的工厂,在创建bean阶段;
三级缓存的特点:
- 一二级缓存保存的是bean的对象,不管是已初始化好的还是未初始化好的,这两个缓存是互斥的,bean不能既在一级缓存又在二级缓存;
- 所有的bean在创建过程中,都会用到第三级缓存,因为bean对象就是通过beanFactory创建出来的;
- 所有的bean最终都会落到第一级缓存;
- 循环依赖,先初始化谁,谁就会入第二级缓存;
大体步骤如下:
- 创建A bean
- 把A beanFactory放进三级缓存
- 给A bean注入B bean
- 发现B bean不存在,创建B bean
- 把B beanFactory放进三级缓存
- 给B bean注入A bean
- 从三级缓存获取到A bean,把A bean放进二级缓存,同时删除三级缓存中的A beanFactory
- 把A bean注入B bean
- B初始化完成,调用addSingleton把B bean放进一级缓存,同时删除二级缓存中的B bean和三级缓存中的B beanFactory(注意:二级缓存中没有B bean,只有A bean)
- 把B bean注入到A bean
- A初始化完成,调用addSingleton把A bean放进一级缓存,同时删除二级缓存中的A bean和三级缓存中的A beanFactory(注意:三级缓存中已没有A beanFactory)
如图:循环依赖在初始化过程中,一共有8次缓存操作:
- 三级缓存2次put,2次remove;
- 二级缓存1次put,1次remove;(都是A bean,循环依赖先初始化谁,谁就会入二级缓存)
- 一级缓存2次put;
看下三级缓存的入库,出库代码:
singletonFactories(第三级缓存)
org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final Object[] args)
throws BeanCreationException {
// 省略................
// Eagerly cache singletons to be able to resolve circular references
// even when triggered by lifecycle interfaces like BeanFactoryAware.
boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
isSingletonCurrentlyInCreation(beanName));
if (earlySingletonExposure) {
if (logger.isDebugEnabled()) {
logger.debug("Eagerly caching bean '" + beanName +
"' to allow for resolving potential circular references");
}
// 调用父类方法把beanFactory对象放入第三级缓存
addSingletonFactory(beanName, new ObjectFactory<Object>() {
@Override
public Object getObject() throws BeansException {
return getEarlyBeanReference(beanName, mbd, bean);
}
});
}
// 省略................
}
父类方法: org.springframework.beans.factory.support.DefaultSingletonBeanRegistry,方法:addSingletonFactory
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);
}
}
}
earlySingletonObjects(第二级缓存)
上面说了只有循环依赖的时候才会用到第二级缓存,入二级缓存的时机则是在后一个bean依赖注入前一个bean的时候,查询到前一个bean的beanFactory,则生成bean放入二级缓存;
对应代码:org.springframework.beans.factory.support.DefaultSingletonBeanRegistry
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
// A bean尚未初始化完成,所以这里返回null
Object singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
synchronized (this.singletonObjects) {
// 尚未放入二级缓存,这里也返回null
singletonObject = this.earlySingletonObjects.get(beanName);
if (singletonObject == null && allowEarlyReference) {
// 从三级缓存得到beanFactory
ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
if (singletonFactory != null) {
// 创建bean对象,放入二级缓存,并清除三级缓存
singletonObject = singletonFactory.getObject();
this.earlySingletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName);
}
}
}
}
return (singletonObject != NULL_OBJECT ? singletonObject : null);
}
二级缓存清除/一级缓存插入逻辑
上面说了一二级缓存是互斥的,那么当bean对象完全初始化好以后,则会调用
org.springframework.beans.factory.support.AbstractBeanFactory
protected <T> T doGetBean(
// 省略。。。。。。。。
// Create bean instance.
if (mbd.isSingleton()) {
// 注意这个Lambda写法,主体是调用getSingleton方法,而第二个参数就是创建完成的bean对象
sharedInstance = getSingleton(beanName, new ObjectFactory<Object>() {
@Override
public Object getObject() throws BeansException {
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);
}
// 省略。。。。。。。。
}
public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
Assert.notNull(beanName, "'beanName' must not be null");
synchronized (this.singletonObjects) {
Object singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null) {
// 省略。。。。。。。。。
// 看这里,如果是新创建bean就调用addSingleton
if (newSingleton) {
addSingleton(beanName, singletonObject);
}
}
return (singletonObject != NULL_OBJECT ? singletonObject : null);
}
}
protected void addSingleton(String beanName, Object singletonObject) {
// 到这里就清楚了,bean入一级缓存,清楚二级缓存
synchronized (this.singletonObjects) {
this.singletonObjects.put(beanName, (singletonObject != null ? singletonObject : NULL_OBJECT));
this.singletonFactories.remove(beanName);
this.earlySingletonObjects.remove(beanName);
this.registeredSingletons.add(beanName);
}
}
总结:
spring解决循环依赖的原理并不复杂,也不高深,非要说有什么原理的话,那就是地址引用,A,B相互依赖,在初始化过程中,大可不用等到对象完全初始化好,而只要实例化出一个光杆对象就可以依赖注入了。