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

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

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

來源: 責(zé)編: 時間:2023-12-13 17:03:12 311觀看
導(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)的呢?74d28資訊網(wǎng)——每日最新資訊28at.com

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

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

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

圖片圖片74d28資訊網(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 必須為單利;74d28資訊網(wǎng)——每日最新資訊28at.com

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

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

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

3. 三級緩存原理

3.1 什么是三級緩存

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

一級緩存(SingletonObjects):

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

二級緩存(EarlySingletonObjects):

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

三級緩存(SingletonFactories):

三級緩存中存儲的是單利工廠緩存,通過調(diào)用該對象的 GetObject 方法,可以獲取到早期暴露出去的 Bean;在該 Bean 要被其他 Bean 引用時,Spring 就會用工廠對象創(chuàng)建出該 Bean 的實例對象,最終當(dāng)該 Bean 完成構(gòu)造的所有步驟后就會將該 Bean 放入到一級緩存中74d28資訊網(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 三級緩存流程

圖片圖片74d28資訊網(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)行處理的,其中包括一級、二級、三級緩存,作用如下:74d28資訊網(wǎng)——每日最新資訊28at.com

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

參考文獻(xiàn)

https://www.51cto.com/article/702892.html74d28資訊網(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)簽:
  • 熱門焦點
  • 掘力計劃第 20 期:Flutter 混合開發(fā)的混亂之治

    在掘力計劃系列活動第20場,《Flutter 開發(fā)實戰(zhàn)詳解》作者,掘金優(yōu)秀作者,Github GSY 系列目負(fù)責(zé)人戀貓的小郭分享了Flutter 混合開發(fā)的混亂之治。Flutter 基于自研的 Skia 引擎
  • 2023 年的 Node.js 生態(tài)系統(tǒng)

    隨著技術(shù)的不斷演進(jìn)和創(chuàng)新,Node.js 在 2023 年達(dá)到了一個新的高度。Node.js 擁有一個龐大的生態(tài)系統(tǒng),可以幫助開發(fā)人員更快地實現(xiàn)復(fù)雜的應(yīng)用。本文就來看看 Node.js 最新的生
  • 一文看懂為蘋果Vision Pro開發(fā)應(yīng)用程序

    譯者 | 布加迪審校 | 重樓蘋果的Vision Pro是一款混合現(xiàn)實(MR)頭戴設(shè)備。Vision Pro結(jié)合了虛擬現(xiàn)實(VR)和增強現(xiàn)實(AR)的沉浸感。其高分辨率顯示屏、先進(jìn)的傳感器和強大的處理能力
  • 2天漲粉255萬,又一賽道在抖音爆火

    來源:運營研究社作者 | 張知白編輯 | 楊佩汶設(shè)計 | 晏談夢潔這個暑期,旅游賽道徹底火了:有的「地方」火了&mdash;&mdash;貴州村超旅游收入 1 個月超過 12 億;有的「博主」火了&m
  • 得物寵物生意「狂飆」,發(fā)力“它經(jīng)濟(jì)”

    作者|花花小萌主近日,得物宣布正式上線寵物鑒別,通過得物App內(nèi)的&ldquo;在線鑒別&rdquo;,可找到鑒別寵物的選項。通過上傳自家寵物的部位細(xì)節(jié),就能收獲擁有專業(yè)資質(zhì)認(rèn)證的得物鑒
  • 阿里大調(diào)整

    來源:產(chǎn)品劉有媒體報道稱,近期淘寶天貓集團(tuán)啟動了近年來最大的人力制度改革,涉及員工績效、層級體系等多個核心事項,目前已形成一個初步的&ldquo;征求意見版&rdquo;:1、取消P序列
  • 疑似小米14外觀設(shè)計圖曝光:后置相機模組變化不大

    下半年的大幕已經(jīng)開啟,而誰將成為下半年手機圈的主角就成為了大家關(guān)注的焦點,其中被傳有望拿下新一代驍龍8 Gen3旗艦芯片的小米14系列更是備受大家矚
  • 信通院:小米、華為等11家應(yīng)用商店基本完成APP簽名及驗簽工作

    中國信通院表示,目前,小米、華為、OPPO、vivo、360手機助手、百度手機助手、應(yīng)用寶、豌豆莢和努比亞等9家應(yīng)用商店,以及抖音和快手2家新型應(yīng)用分發(fā)平
  • 英特爾Xe HPG游戲顯卡:擁有512EU,單風(fēng)扇版本

    據(jù)10 月 30 日外媒 TheVerge 消息報道,英特爾 Xe HPG Arc Alchemist 的正面實被曝光,不僅擁有 512 EU 版顯卡,還擁有 128EU 的單風(fēng)扇版本。另外,這款顯卡 PCB
Top 主站蜘蛛池模板: 贵阳市| 宝鸡市| 南江县| 若尔盖县| 长顺县| 夹江县| 长宁区| 田东县| 玉林市| 咸宁市| 松桃| 疏附县| 平塘县| 仙游县| 朔州市| 镇雄县| 桐庐县| 三门县| 山阴县| 胶南市| 犍为县| 香格里拉县| 九台市| 渭源县| 靖安县| 旺苍县| 赤城县| 民乐县| 黄山市| 乐山市| 翼城县| 辽中县| 长乐市| 望都县| 会昌县| 东明县| 龙里县| 榕江县| 青海省| 固原市| 吉首市|