Spring如何使用三級緩存解決循環(huán)依賴
1. 前言
在日常開發(fā)中,Bean之間的循環(huán)依賴非常常見,Spring 已經(jīng)幫我們做到使用無感知處理,那么 Spring 是如何實現(xiàn)的呢?
2. 循環(huán)依賴簡介
2.1 什么是循環(huán)依賴
循環(huán)依賴是指兩個或多個對象存在相互依賴、相互引用的關系,而這種引用形成一個環(huán)時,就會出現(xiàn)循環(huán)引用,如圖:
圖片
public class PersonA {
@Autowired
private PersonB personB;
}
public class PersonB {
@Autowired
private PersonA personA;
}
2.2 Spring 處理循環(huán)依賴的前提條件
1.相互依賴的 Bean 必須為單利;
因為如果每次請求都創(chuàng)建一個 Bean,那么在處理循環(huán)依賴的時候,每次都會產(chǎn)生一個新的 Bean 實例,由于沒有全局的實例 Bean 緩存,則無法處理循環(huán)依賴
2.依賴注入的方式不能都是構(gòu)造函數(shù)注入的方式。
使用構(gòu)造函數(shù)注入,Bean 實例在構(gòu)造函數(shù)沒有完全被調(diào)用時是不會創(chuàng)建的;因為 PersonA 引用 PersonB,PersonB 又引用 PersonA,兩者都無法進行初始化,產(chǎn)生了死鎖
3. 三級緩存原理
3.1 什么是三級緩存
Spring 是通過三級緩存的方式處理循環(huán)依賴,三級緩存是 Spring Bean 在各個階段的緩存
一級緩存(SingletonObjects):
存放已經(jīng)完全實例化、初始化的bean,實現(xiàn)了單利bean只會實例化和初始化一次
二級緩存(EarlySingletonObjects):
存放早期暴露出來的Bean對象,bean的生命周期還未完成(未完成屬性注入與初始化的bean)
三級緩存(SingletonFactories):
三級緩存中存儲的是單利工廠緩存,通過調(diào)用該對象的 GetObject 方法,可以獲取到早期暴露出去的 Bean;在該 Bean 要被其他 Bean 引用時,Spring 就會用工廠對象創(chuàng)建出該 Bean 的實例對象,最終當該 Bean 完成構(gòu)造的所有步驟后就會將該 Bean 放入到一級緩存中
/** 一級緩存 */
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<String, Object>(256);
/** 二級緩存 */
private final Map<String, Object> earlySingletonObjects = new HashMap<String, Object>(16);
/** 三級緩存 */
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<String, ObjectFactory<?>>(16);
3.2 三級緩存流程
圖片
3.3 三級緩存源碼解析
創(chuàng)建 Bean 主要的方法是 AbstractBeanFactory.doGetBean 方法
protected <T> T doGetBean( String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly) throws BeansException {
// 獲取bean的規(guī)范名稱
String beanName = transformedBeanName(name);
Object bean;
// 從各級緩存中獲取bean對象
Object sharedInstance = getSingleton(beanName);
// 跟factoryBean相關判斷
if (sharedInstance != null && args == null) {
...
}
// 獲取factorybean的真是bean
//若為普通bean則直接返回對象
bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
}
......
// 創(chuàng)建單利bean對象
if (mbd.isSingleton()) {
sharedInstance = getSingleton(beanName, () -> {
try {
// 創(chuàng)建bean
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);
}
......
// 返回bean對象 return (T) bean; }
我們看兩個比較重要獲取 Bean 的方法 GetSingleton()
// 這個方法主要是三級緩存容器,思路大概是:從一級緩存查詢,若找不到去二級緩存查詢,還是不存在則去三級緩存,若三級緩存找到了,則將bean放入二級緩存中
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
// 從一級緩存中查找bean
Object singletonObject = this.singletonObjects.get(beanName);
// 判斷一級緩存查找不到bean && bean是否處于創(chuàng)建中,成立,則進入循環(huán)依賴
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
synchronized (this.singletonObjects) {
// 從二級緩存中查找
singletonObject = this.earlySingletonObjects.get(beanName);
// 二級緩存未查詢到 && 是否允許獲取早期引用
if (singletonObject == null && allowEarlyReference) {
// 從三級緩存查詢
ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
// 三級緩存存在bean
if (singletonFactory != null) {
// 獲取bean實例
singletonObject = singletonFactory.getObject();
// 從三級緩存升級到二級緩存,
this.earlySingletonObjects.put(beanName, singletonObject);
// 三級緩存中移除
this.singletonFactories.remove(beanName);
}
}
}
}
// 返回bean
return singletonObject;
}
public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
Assert.notNull(beanName, "Bean name must not be null");
synchronized (this.singletonObjects) {
// 從一級緩存中獲取對應bean
Object singletonObject = this.singletonObjects.get(beanName);
// 若bean不存在
if (singletonObject == null) {
// 當前正在銷毀bean,不能創(chuàng)建
if (this.singletonsCurrentlyInDestruction) {
throw new BeanCreationNotAllowedException(beanName, "Singleton bean creation not allowed while singletons of this factory are in destruction " + "(Do not request a bean from a BeanFactory in a destroy method implementation!)");
}
if (logger.isDebugEnabled()) {
logger.debug("Creating shared instance of singleton bean '" + beanName + "'");
}
// 創(chuàng)建前檢查,記錄正在加載狀態(tài)
beforeSingletonCreation(beanName);
boolean newSingleton = false;
boolean recordSuppressedExceptions = (this.suppressedExceptions == null);
// 如果當前沒有異常,初始化異常集合
if (recordSuppressedExceptions) {
this.suppressedExceptions = new LinkedHashSet<>();
}
try {
// 執(zhí)行匿名內(nèi)部類方法
singletonObject = singletonFactory.getObject();
newSingleton = true;
}
catch(IllegalStateException ex){
// 執(zhí)行getObject方法創(chuàng)建bean
singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null) {
throw ex;
}
} catch(BeanCreationException ex){
if (recordSuppressedExceptions) {
or (Exception suppressedException : this.suppressedExceptions) {
ex.addRelatedCause(suppressedException);
}
}
throw ex;
} finally{
if (recordSuppressedExceptions) {
this.suppressedExceptions = null;
}
// 單例bean創(chuàng)建完成后,容器移除bean
afterSingletonCreation(beanName);
}
// newSingleton為true時,表示bean創(chuàng)建成功
// 判斷是否為新的完成整bean
if (newSingleton) {
// 將bean存入一級緩存中
addSingleton(beanName, singletonObject);
}
}
return singletonObject;
}
}
添加與清理緩存
// 將bean放入一級緩存切清楚二級、三級緩存
protected void addSingleton(String beanName, Object singletonObject) {
synchronized (this.singletonObjects) {xw
// 添加到一級緩存中
this.singletonObjects.put(beanName, singletonObject);
// 從三級緩存中移除
this.singletonFactories.remove(beanName);
// 從二級緩存中移除
this.earlySingletonObjects.remove(beanName);
// 放入已注冊的單利池中
this.registeredSingletons.add(beanName);
}
}
// 添加到三級緩存
protected void addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory) {
synchronized (this.singletonObjects) {
// 若一級緩存不存在bean實例
if (!this.singletonObjects.containsKey(beanName)) {
// 添加到三級緩存
this.singletonFactories.put(beanName, singletonFactory);
// 從第二級緩存刪除
this.earlySingletonObjects.remove(beanName);
// 放入已注冊的單例池里
this.registeredSingletons.add(beanName);
}
}
4.總結(jié)
Spring 循環(huán)依賴是通過map緩存進行處理的,其中包括一級、二級、三級緩存,作用如下:
- 一級緩存SingletonObjects實例化、初始化實例。
- 二級緩存EarlySingletonObjects存放的是早期的 Bean ,半成品還未初始化的 bean。
- 三級緩存SingletonFactories是一個對象工廠,用于創(chuàng)建對象,然后放入到二級緩存中。同時對象如果存在 Aop 代理,那么返回的對象就是代理對象。
參考文獻
http://www.scjtxx.cn/article/702892.html