一、什麼是循環依賴
Spring中的bean存在循環嵌套依賴的情況就叫做循環依賴
如下圖:
- 情況一:A依賴着B,B也依賴着A,這是循環依賴
- 情況二:A依賴着B,B也依賴着C,C依賴着A,這是循環依賴
二、循環依賴的Demo
@Component
public class A {
@Autowired
private B b;
......
}
@Component
public class B {
@Autowired
private A a;
......
}
三、Spring解決循環依賴的源碼分析
Spring循環依賴出現在創建bean時,首先調用AbstractBeanFactory#getBean()方法獲取bean
getBean(beanName)
@Override
public Object getBean(String name) throws BeansException {
return doGetBean(name, null, null, false);
}
doGetBean(name, null, null, false)
protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType, @Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {
// 根據beanName嘗試從三級緩存中獲取bean實例
Object sharedInstance = getSingleton(beanName);
// 當三級緩存中存在此bean,表示當前該bean已創建完成 || 正在創建
if (sharedInstance != null && args == null) {
// 返回對應的實例,有時候存在諸如BeanFactory的情況並不是直接返回實例本身而是返回指定方法返回的實例
// 如果sharedInstance是普通的單例bean,下面的方法會直接返回,但如果sharedInstance是FactoryBean類型的,
// 則需要調用getObject工廠方法獲取bean實例,如果用戶想獲取FactoryBean本身,這裏也不會做特別的處理
bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
}
// 當bean還未創建
else {
// 這一大段代碼省略
......
// 正式開始創建bean實例
if (mbd.isSingleton()) { // 當該bean的scope爲singleton或者爲空時
sharedInstance = getSingleton(beanName, () -> { // 從三級緩存中獲取bean實例
try {
return createBean(beanName, mbd, args); // 真正創建bean
}
catch (BeansException ex) {
}
});
bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}
}
// 創建bean的後續處理
......
return (T) bean;
}
getSingleton(beanName)
/**
* 嘗試從三級緩存中獲取bean實例
*
* 從一級緩存(單例池) -> 二級緩存 -> 三級緩存依次獲取,當三級緩存中都不存在bean實例時,那個該bean處於還未創建的狀態
*
* 這裏解釋一下三級緩存分別的作用
*/
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
// 嘗試從三級緩存中獲取bean實例
Object singletonObject = this.singletonObjects.get(beanName); // 從一級緩存中獲取bean
// 如果一級緩存中不存在該bean實例 && 該bean正在創建中
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) { // isSingletonCurrentlyInCreation(beanName)判斷這個bean是否在創建過程中,對象是否有循環依賴
synchronized (this.singletonObjects) {
singletonObject = this.earlySingletonObjects.get(beanName); // 嘗試從二級緩存中獲取提前曝光的bean實例
// 如果二級緩存中不存在giantbean實例 && 允許從singletonFactories從獲取bean實例
if (singletonObject == null && allowEarlyReference) {
ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName); // 從三級緩存中獲取bean實例
// 如果bean存在,將該bean實例從三級緩存升級到二級緩存中提前曝光bean實例,並且從三級緩存中刪除
if (singletonFactory != null) {
singletonObject = singletonFactory.getObject();
this.earlySingletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName);
}
}
}
}
return singletonObject;
}
createBean(beanName, mbd, args)
protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) throws BeanCreationException {
// 這一大段代碼省略
......
// 實例化bean
Object beanInstance = doCreateBean(beanName, mbdToUse, args);
return beanInstance;
}
doCreateBean(beanName, mbdToUse, args)
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args) throws BeanCreationException {
// 這一大段代碼省略
......
// 創建bean實例轉化成BeanWrapper對象
if (instanceWrapper == null) {
// 調用bean的構造方法進行初始化,經過這一步,bean屬性並沒有被賦值,只是一個空殼,這是bean初始化的【早期對象】
instanceWrapper = createBeanInstance(beanName, mbd, args);
}
......
// 判斷bean是否存在循環依賴
// 如果當前bean是單例,且支持循環依賴,且當前bean正在創建,通過往singletonFactories添加一個objectFactory,這樣後期如果有其他bean依賴該bean 可以從singletonFactories獲取到bean
boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
isSingletonCurrentlyInCreation(beanName));
if (earlySingletonExposure) {
// 添加工廠對象到singletonFactories緩存中,【提前暴露早期對象】
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
}
// 給已經已經初始化的屬性賦值,包括完成bean的依賴注入
populateBean(beanName, mbd, instanceWrapper);
......
return exposedObject;
}
populateBean(beanName, mbd, instanceWrapper)
protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
// 這一大段代碼省略
......
// 爲屬性賦值
applyPropertyValues(beanName, mbd, bw, pvs);
}
applyPropertyValues(beanName, mbd, bw, pvs)
protected void applyPropertyValues(String beanName, BeanDefinition mbd, BeanWrapper bw, PropertyValues pvs) {
// 這一大段代碼省略
......
// 爲當前bean中屬性賦值,包括依賴注入的屬性
Object resolvedValue = valueResolver.resolveValueIfNecessary(pv, originalValue);
// 這一大段代碼省略
......
}
valueResolver.resolveValueIfNecessary(pv, originalValue)
/**
* 如果當前初始化的bean有屬性需要注入的,將會調用resolveReference(argName, ref)來返回需要注入的bean
*/
public Object resolveValueIfNecessary(Object argName, @Nullable Object value) {
// 獲取需要依賴注入屬性的值
if (value instanceof RuntimeBeanReference) {
RuntimeBeanReference ref = (RuntimeBeanReference) value;
return resolveReference(argName, ref);
}
// 這一大段代碼省略
......
}
resolveReference(argName, ref)
/**
* 在該方法中,會爲當前初始化bean主要爲屬性注入另外一個bean,調用getBean()方法獲取需要注入的bean,最終注入到屬性中
*/
private Object resolveReference(Object argName, RuntimeBeanReference ref) {
try {
Object bean;
String refName = ref.getBeanName();
refName = String.valueOf(doEvaluate(refName));
if (ref.isToParent()) {
if (this.beanFactory.getParentBeanFactory() == null) {
throw new BeanCreationException(
this.beanDefinition.getResourceDescription(), this.beanName,
"Can't resolve reference to bean '" + refName +
"' in parent factory: no parent factory available");
}
bean = this.beanFactory.getParentBeanFactory().getBean(refName);
}
else {
// 當前初始化bean主要爲屬性注入另外一個bean,調用getBean()方法獲取需要注入的bean,最終注入到屬性中
bean = this.beanFactory.getBean(refName);
this.beanFactory.registerDependentBean(refName, this.beanName);
}
if (bean instanceof NullBean) {
bean = null;
}
return bean;
}
catch (BeansException ex) {
throw new BeanCreationException(
this.beanDefinition.getResourceDescription(), this.beanName,
"Cannot resolve reference to bean '" + ref.getBeanName() + "' while setting " + argName, ex);
}
}
調用getBean()
方法又回到了開頭的getBean(beanName)
,此時去實例化B,實例化B的時候一步執行剛纔實例bean A的步驟,然後到了調用populateBean(beanName, mbd, instanceWrapper)
方法注入bean A,又回到第二次實例化bean A,在調用getSingleton(beanName)
方法嘗試從三級緩存中獲取bean實例時,從第三級緩存singletonFactories
中獲取到正在創建的bean A,這樣就獲取到bean A了,然後返回給bean B注入到bean B的屬性中,完成bean B的初始化了,最後返回給bean A注入到bean A的屬性中,這樣就完成了循環依賴了。初始化bean A和bean B的流程圖如下: