日韩成人免费在线_国产成人一二_精品国产免费人成电影在线观..._日本一区二区三区久久久久久久久不

當(dāng)前位置:首頁 > 科技  > 軟件

Spring如何使用三級緩存解決循環(huán)依賴

來源: 責(zé)編: 時間:2023-12-13 17:03:12 347觀看
導(dǎo)讀1. 前言在日常開發(fā)中,Bean之間的循環(huán)依賴非常常見,Spring 已經(jīng)幫我們做到使用無感知處理,那么 Spring 是如何實現(xiàn)的呢?2. 循環(huán)依賴簡介2.1 什么是循環(huán)依賴循環(huán)依賴是指兩個或多個對象存在相互依賴、相互引用的關(guān)系,而這種

1. 前言

在日常開發(fā)中,Bean之間的循環(huán)依賴非常常見,Spring 已經(jīng)幫我們做到使用無感知處理,那么 Spring 是如何實現(xiàn)的呢?9s328資訊網(wǎng)——每日最新資訊28at.com

2. 循環(huán)依賴簡介

2.1 什么是循環(huán)依賴

循環(huán)依賴是指兩個或多個對象存在相互依賴、相互引用的關(guān)系,而這種引用形成一個環(huán)時,就會出現(xiàn)循環(huán)引用,如圖:9s328資訊網(wǎng)——每日最新資訊28at.com

圖片圖片9s328資訊網(wǎng)——每日最新資訊28at.com

public class PersonA {   @Autowired  private PersonB personB;}
public class PersonB {  @Autowired  private PersonA personA;}

2.2 Spring 處理循環(huán)依賴的前提條件

1.相互依賴的 Bean 必須為單利;9s328資訊網(wǎng)——每日最新資訊28at.com

因為如果每次請求都創(chuàng)建一個 Bean,那么在處理循環(huán)依賴的時候,每次都會產(chǎn)生一個新的 Bean 實例,由于沒有全局的實例 Bean 緩存,則無法處理循環(huán)依賴9s328資訊網(wǎng)——每日最新資訊28at.com

2.依賴注入的方式不能都是構(gòu)造函數(shù)注入的方式。9s328資訊網(wǎng)——每日最新資訊28at.com

使用構(gòu)造函數(shù)注入,Bean 實例在構(gòu)造函數(shù)沒有完全被調(diào)用時是不會創(chuàng)建的;因為 PersonA 引用 PersonB,PersonB 又引用 PersonA,兩者都無法進(jìn)行初始化,產(chǎn)生了死鎖9s328資訊網(wǎng)——每日最新資訊28at.com

3. 三級緩存原理

3.1 什么是三級緩存

Spring 是通過三級緩存的方式處理循環(huán)依賴,三級緩存是 Spring Bean 在各個階段的緩存9s328資訊網(wǎng)——每日最新資訊28at.com

一級緩存(SingletonObjects):

存放已經(jīng)完全實例化、初始化的bean,實現(xiàn)了單利bean只會實例化和初始化一次9s328資訊網(wǎng)——每日最新資訊28at.com

二級緩存(EarlySingletonObjects):

存放早期暴露出來的Bean對象,bean的生命周期還未完成(未完成屬性注入與初始化的bean)9s328資訊網(wǎng)——每日最新資訊28at.com

三級緩存(SingletonFactories):

三級緩存中存儲的是單利工廠緩存,通過調(diào)用該對象的 GetObject 方法,可以獲取到早期暴露出去的 Bean;在該 Bean 要被其他 Bean 引用時,Spring 就會用工廠對象創(chuàng)建出該 Bean 的實例對象,最終當(dāng)該 Bean 完成構(gòu)造的所有步驟后就會將該 Bean 放入到一級緩存中9s328資訊網(wǎng)——每日最新資訊28at.com

/** 一級緩存 */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 三級緩存流程

圖片圖片9s328資訊網(wǎng)——每日最新資訊28at.com

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相關(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 的方法 GetSingleton()

// 這個方法主要是三級緩存容器,思路大概是:從一級緩存查詢,若找不到去二級緩存查詢,還是不存在則去三級緩存,若三級緩存找到了,則將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);  }}

4.總結(jié)

Spring 循環(huán)依賴是通過map緩存進(jìn)行處理的,其中包括一級、二級、三級緩存,作用如下:9s328資訊網(wǎng)——每日最新資訊28at.com

  • 一級緩存SingletonObjects實例化、初始化實例。
  • 二級緩存EarlySingletonObjects存放的是早期的 Bean ,半成品還未初始化的 bean。
  • 三級緩存SingletonFactories是一個對象工廠,用于創(chuàng)建對象,然后放入到二級緩存中。同時對象如果存在 Aop 代理,那么返回的對象就是代理對象。

參考文獻(xiàn)

https://www.51cto.com/article/702892.html9s328資訊網(wǎng)——每日最新資訊28at.com

本文鏈接:http://www.www897cc.com/showinfo-26-44423-0.htmlSpring如何使用三級緩存解決循環(huán)依賴

聲明:本網(wǎng)頁內(nèi)容旨在傳播知識,若有侵權(quán)等問題請及時與本網(wǎng)聯(lián)系,我們將在第一時間刪除處理。郵件:2376512515@qq.com

上一篇: 在終端里輸入 npm start 后都發(fā)生了啥

下一篇: 時尚更多元 三星 Galaxy Watch6 系列助你完美解鎖冬日氛圍感

標(biāo)簽:
  • 熱門焦點
  • 小米平板5 Pro 12.4簡評:多專多能 兼顧影音娛樂的大屏利器

    疫情帶來了網(wǎng)課,網(wǎng)課盤活了安卓平板,安卓平板市場雖然中途停滯了幾年,但好的一點就是停滯的這幾年行業(yè)又有了新的發(fā)展方向,例如超窄邊框、高刷新率、多攝鏡頭組合等,這就讓安卓
  • Rust中的高吞吐量流處理

    作者 | Noz編譯 | 王瑞平本篇文章主要介紹了Rust中流處理的概念、方法和優(yōu)化。作者不僅介紹了流處理的基本概念以及Rust中常用的流處理庫,還使用這些庫實現(xiàn)了一個流處理程序
  • JVM優(yōu)化:實戰(zhàn)OutOfMemoryError異常

    一、Java堆溢出堆內(nèi)存中主要存放對象、數(shù)組等,只要不斷地創(chuàng)建這些對象,并且保證 GC Roots 到對象之間有可達(dá)路徑來避免垃 圾收集回收機(jī)制清除這些對象,當(dāng)這些對象所占空間超過
  • 2023年,我眼中的字節(jié)跳動

    此時此刻(2023年7月),字節(jié)跳動從未上市,也從未公布過任何官方的上市計劃;但是這并不妨礙它成為中國最受關(guān)注的互聯(lián)網(wǎng)公司之一。從2016-17年的抖音強(qiáng)勢崛起,到2018年的&ldquo;頭騰
  • 品牌洞察丨服務(wù)本地,美團(tuán)直播成效幾何?

    來源:17PR7月11日,美團(tuán)App首頁推薦位出現(xiàn)&ldquo;美團(tuán)直播&rdquo;的固定入口。在直播聚合頁面,外賣&ldquo;神槍手&rdquo;直播間、美團(tuán)旅行直播間、美團(tuán)買菜直播間等均已上線,同時
  • 當(dāng)家的盒馬,加速謀生

    來源 | 價值星球Planet作者 | 歸去來自己&ldquo;當(dāng)家&rdquo;的盒馬,開始加速謀生了。據(jù)盒馬官微消息,盒馬計劃今年開放生鮮供應(yīng)鏈,將其生鮮商品送往食堂。目前,盒馬在上海已經(jīng)與
  • 造車兩年股價跌六成,小米的估值邏輯變了嗎?

    如果從小米官宣造車后的首個交易日起持有小米集團(tuán)的股票,那么截至2023年上半年最后一個交易日,投資者將浮虧59.16%,同區(qū)間的恒生科技指數(shù)跌幅為52.78%
  • 余承東:AI大模型技術(shù)的發(fā)展將會帶來下一代智能終端操作系統(tǒng)的智慧體驗

    8月4日消息,2023年華為開發(fā)者大會(HDC.Together)今天正式開幕,華為發(fā)布HarmonyOS 4、全新升級的鴻蒙開發(fā)套件、HarmonyOS Next開發(fā)者預(yù)覽版本等一系列
  • 華為Mate 60保護(hù)殼曝光:碩大后置相機(jī)模組 凸起程度有驚喜

    這段時間以來,關(guān)于華為新旗艦的爆料日漸密集。據(jù)此前多方爆料,今年華為將開始恢復(fù)一年雙旗艦戰(zhàn)略,除上半年推出的P60系列外,往年下半年的Mate系列也將
Top 主站蜘蛛池模板: 乌什县| 巴里| 扶绥县| 桑日县| 科尔| 乌拉特中旗| 黎川县| 青阳县| 邵阳市| 高雄市| 贵州省| 梅河口市| 汪清县| 湘阴县| 江达县| 泰兴市| 海口市| 太谷县| 滨州市| 米林县| 大港区| 运城市| 抚远县| 安吉县| 梁平县| 苍梧县| 宜君县| 麻栗坡县| 宣汉县| 个旧市| 兴义市| 沁阳市| 新干县| 凉城县| 嘉黎县| 浦江县| 塔城市| 武穴市| 台南市| 辽宁省| 社会|