在日常開發(fā)中,Bean之間的循環(huán)依賴非常常見,Spring 已經(jīng)幫我們做到使用無感知處理,那么 Spring 是如何實現(xiàn)的呢?
循環(huán)依賴是指兩個或多個對象存在相互依賴、相互引用的關(guān)系,而這種引用形成一個環(huán)時,就會出現(xiàn)循環(huán)引用,如圖:
圖片
public class PersonA { @Autowired private PersonB personB;}
public class PersonB { @Autowired private PersonA personA;}
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,兩者都無法進(jìn)行初始化,產(chǎn)生了死鎖
Spring 是通過三級緩存的方式處理循環(huán)依賴,三級緩存是 Spring Bean 在各個階段的緩存
存放已經(jīng)完全實例化、初始化的bean,實現(xiàn)了單利bean只會實例化和初始化一次
存放早期暴露出來的Bean對象,bean的生命周期還未完成(未完成屬性注入與初始化的bean)
三級緩存中存儲的是單利工廠緩存,通過調(diào)用該對象的 GetObject 方法,可以獲取到早期暴露出去的 Bean;在該 Bean 要被其他 Bean 引用時,Spring 就會用工廠對象創(chuàng)建出該 Bean 的實例對象,最終當(dāng)該 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);
圖片
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相關(guān)判斷 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放入二級緩存中protected Object getSingleton(String beanName, boolean allowEarlyReference) { // 從一級緩存中查找bean Object singletonObject = this.singletonObjects.get(beanName); // 判斷一級緩存查找不到bean && bean是否處于創(chuàng)建中,成立,則進(jìn)入循環(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) { // 從一級緩存中獲取對應(yīng)bean Object singletonObject = this.singletonObjects.get(beanName); // 若bean不存在 if (singletonObject == null) { // 當(dāng)前正在銷毀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); // 如果當(dāng)前沒有異常,初始化異常集合 if (recordSuppressedExceptions) { this.suppressedExceptions = new LinkedHashSet<>(); } try { // 執(zhí)行匿名內(nèi)部類方法 singletonObject = singletonFactory.getObject(); newSingleton = true; } catch(IllegalStateException ex){ // 執(zhí)行g(shù)etObject方法創(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); }}
Spring 循環(huán)依賴是通過map緩存進(jìn)行處理的,其中包括一級、二級、三級緩存,作用如下:
https://www.51cto.com/article/702892.html
本文鏈接:http://www.www897cc.com/showinfo-26-44423-0.htmlSpring如何使用三級緩存解決循環(huán)依賴
聲明:本網(wǎng)頁內(nèi)容旨在傳播知識,若有侵權(quán)等問題請及時與本網(wǎng)聯(lián)系,我們將在第一時間刪除處理。郵件:2376512515@qq.com