欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

關(guān)于spring三級緩存的解讀

 更新時間:2025年02月12日 09:28:45   作者:ambity_lyf  
Spring三級緩存解決循環(huán)依賴、AOP和多線程問題,包括singletonObjects、earlySingletonObjects和singletonFactories三層緩存,通過不同方法獲取bean并解決這些問題

spring三級緩存的解讀

spring 中為了解決 B的重復(fù)利用,A 依賴B 的循環(huán)依賴,aop 問題,多線程可能拿到不完整的bean 的問題引入了3層緩存,分別是

/** Cache of singleton objects: bean name to bean instance. */
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);

/** Cache of early singleton objects: bean name to bean instance. */
private final Map<String, Object> earlySingletonObjects = new HashMap<>(16);

/** Cache of singleton factories: bean name to ObjectFactory. */
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);
  • singletonObjects 用于存放單例bean 實例
  • earlySingletonObjects 用于存放早期的bean 實例
  • singletonFactories 用于存放簡單工廠實例

從3級緩存中 獲取bean 的方法有如下兩個

1.從緩存中獲取,主要用來解決循環(huán)依賴問題

protected Object getSingleton(String beanName, boolean allowEarlyReference) {
   // 這里不用考慮指令重排,因為 bean 初始化完成后才會放入map
   Object singletonObject = this.singletonObjects.get(beanName);
   if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
      // 加鎖,與另一個getSingleton 方法 互斥訪問,保證并發(fā)情況下獲取到不完整的bean
      synchronized (this.singletonObjects) {
         singletonObject = this.earlySingletonObjects.get(beanName);
         if (singletonObject == null && allowEarlyReference) {
            // 獲取工廠bean ,因為可能是aop 生成的代理,這里二級和三級緩存保證獲取到的bean 是最后的完整bean
            ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
            if (singletonFactory != null) {
               singletonObject = singletonFactory.getObject();
               // 放入 二級緩存中,從3級緩存中移除
               this.earlySingletonObjects.put(beanName, singletonObject);
               this.singletonFactories.remove(beanName);
            }
         }
      }
   }
   return singletonObject;
}

2.創(chuàng)建bean 的真正邏輯

public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
   Assert.notNull(beanName, "Bean name must not be null");
   synchronized (this.singletonObjects) {
      // 再次從一級緩存中獲取,因為多線程加載同一個bean 時,
      //相當(dāng)于 雙重檢查
      Object singletonObject = this.singletonObjects.get(beanName);
      if (singletonObject == null) {
         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 + "'");
         }
         // 標(biāo)記bean 正在創(chuàng)建
         beforeSingletonCreation(beanName);
         boolean newSingleton = false;
         boolean recordSuppressedExceptions = (this.suppressedExceptions == null);
         if (recordSuppressedExceptions) {
            this.suppressedExceptions = new LinkedHashSet<>();
         }
         try {
            singletonObject = singletonFactory.getObject();
            newSingleton = true;
         }
         catch (IllegalStateException ex) {
            // Has the singleton object implicitly appeared in the meantime ->
            // if yes, proceed with it since the exception indicates that state.
            singletonObject = this.singletonObjects.get(beanName);
            if (singletonObject == null) {
               throw ex;
            }
         }
         catch (BeanCreationException ex) {
            if (recordSuppressedExceptions) {
               for (Exception suppressedException : this.suppressedExceptions) {
                  ex.addRelatedCause(suppressedException);
               }
            }
            throw ex;
         }
         finally {
            if (recordSuppressedExceptions) {
               this.suppressedExceptions = null;
            }
            afterSingletonCreation(beanName);
         }
         if (newSingleton) {
            addSingleton(beanName, singletonObject);
         }
      }
      return singletonObject;
   }
}

我們先假設(shè)不存在aop 與多線程競爭的情況,此時我們只需要一級緩存就可以解決循環(huán)依賴的問題

  • 1.構(gòu)造bean A ->
  • 2.把A 放入 map1 ->
  • 3. 填充A的屬性 ->
  • 4.創(chuàng)建bean B ->
  • 5.填充B->
  • 6.從緩存中拿到A->
  • 7.返回B ->
  • 8返回A

即不存在aop且不考慮多線程的情況下,只要一個map1 我們就能解決循環(huán)依賴的問題

3.現(xiàn)在我們考慮aop

假設(shè)A 有屬性B ,B 有屬性A ,且我們對A 做了aop,在創(chuàng)建B 的時候我們希望拿到的是A 的aop 代理對象,此時假設(shè)填充B 的時候獲取A ,

假設(shè)如果我們用一層緩存解決?

可以對是否aop 代理過存儲一個標(biāo)志位,此時必然在后面獲取bean 的時候都要多一層判斷,所以此時需要二層緩存來解決

一層存放aop 代理過的對象或不需要aop 的對象,一層存放非aop 對象,即創(chuàng)建工廠。

4.我們再考慮并發(fā)的情況,即多線程獲取一個單例

這里如果熟悉單例模式的創(chuàng)建過程,就不難理解第二個方法中的synchronized 與加鎖后再次嘗試從一級緩存中獲取,把第一個方法可以看作第一次非空判斷,那么就是雙重鎖檢查保證單例。但是只做了雙重鎖檢查保證單例可以支持多線程操作嗎?

答案是否定的,假設(shè)我們?yōu)榱私鉀Qaop 使用了二層緩存,對于A 來說 并沒有完全完成賦值和初始化的操作,但是由于A 依賴B ,B依賴于A的aop 代理對象,此時A 已經(jīng)在一級中了,那么線程2邊能從map1 中獲取到 對象A,(當(dāng)然你也可以對整個創(chuàng)建過程加鎖,那么就不存在多線程問題)。但是此時A 對象并沒有完成賦值與init 的方法執(zhí)行,這樣很容易造成線程2 的異常,所以還需要一層緩存將完成整個創(chuàng)建過程的bean ,與沒有創(chuàng)建完成的純潔bean 隔離開,所以才有了3級緩存。

此時再考慮3級緩存的獲取,基于并發(fā)的考慮就不難理解第一個方法為何要synchronized 了,即保證并發(fā)下,緩存只在一層緩存中存在。

綜上來說,我的理解,aop 問題需要兩層緩存來解決,而考慮多線程并發(fā)的情況下,所以需要三層緩存來解決。

總結(jié)

以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。

相關(guān)文章

  • 詳解spring注解式參數(shù)校驗

    詳解spring注解式參數(shù)校驗

    本篇文章主要介紹了詳解spring注解式參數(shù)校驗,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-06-06
  • JavaScript中的isTrusted屬性及其應(yīng)用場景詳解

    JavaScript中的isTrusted屬性及其應(yīng)用場景詳解

    在現(xiàn)代 Web 開發(fā)中,JavaScript 是構(gòu)建交互式應(yīng)用的核心語言,隨著前端技術(shù)的不斷發(fā)展,開發(fā)者需要處理越來越多的復(fù)雜場景,例如事件處理、數(shù)據(jù)傳遞和狀態(tài)管理等,本文將通過一個實際案例,深入探討 isTrusted 屬性的來源、作用,需要的朋友可以參考下
    2025-01-01
  • java中l(wèi)ong和Long有什么區(qū)別詳解

    java中l(wèi)ong和Long有什么區(qū)別詳解

    這篇文章主要介紹了Java中l(wèi)ong和Long是基本數(shù)據(jù)類型和包裝數(shù)據(jù)類型的區(qū)別,包括默認值、內(nèi)存占用、使用場景、方法支持以及裝箱和拆箱,包裝數(shù)據(jù)類型如Integer提供了許多有用的方法,需要的朋友可以參考下
    2025-02-02
  • SpringBoot創(chuàng)建自定義starter詳解

    SpringBoot創(chuàng)建自定義starter詳解

    這篇文章主要介紹了SpringBoot創(chuàng)建自定義starter詳解,Starter是Spring Boot中的一個非常重要的概念,Starter相當(dāng)于模塊,它能將模塊所需的依賴整合起來并對模塊內(nèi)的Bean根據(jù)環(huán)境(條件)進行自動配置,需要的朋友可以參考下
    2024-01-01
  • Java解析XML文件開源庫DOM4J

    Java解析XML文件開源庫DOM4J

    dom4j是一個Java的XML API,是jdom的升級品,用來讀寫XML文件的。dom4j是一個十分優(yōu)秀的JavaXML API,具有性能優(yōu)異、功能強大和極其易使用的特點,它的性能超過sun公司官方的dom技術(shù),同時它也是一個開放源代碼的軟件
    2023-01-01
  • 詳細聊聊Mybatis中萬能的Map

    詳細聊聊Mybatis中萬能的Map

    最近有個需求,就是使用mybatis時,向mysql中插入數(shù)據(jù),其參數(shù)為map類型,下面這篇文章主要給大家介紹了關(guān)于Mybatis中萬能的Map的相關(guān)資料,需要的朋友可以參考下
    2021-12-12
  • 徹底解決Spring mvc中時間的轉(zhuǎn)換和序列化等問題

    徹底解決Spring mvc中時間的轉(zhuǎn)換和序列化等問題

    這篇文章主要介紹了徹底解決Spring mvc中時間的轉(zhuǎn)換和序列化等問題,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-09-09
  • Java中File與byte[]的互轉(zhuǎn)方式

    Java中File與byte[]的互轉(zhuǎn)方式

    這篇文章主要介紹了Java中File與byte[]的互轉(zhuǎn)方式,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2024-05-05
  • springboot2.1.3配置sftp自定義sftp連接池的詳細過程

    springboot2.1.3配置sftp自定義sftp連接池的詳細過程

    這篇文章主要介紹了springboot2.1.3配置sftp自定義sftp連接池的詳細過程,本文給大家介紹的非常詳細,對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2021-08-08
  • java實現(xiàn)操作系統(tǒng)的短進程作業(yè)調(diào)度示例分享

    java實現(xiàn)操作系統(tǒng)的短進程作業(yè)調(diào)度示例分享

    java編寫的實現(xiàn)了操作系統(tǒng)中的短作業(yè)進程,可以實現(xiàn)幾道作業(yè)同時作業(yè)調(diào)度
    2014-02-02

最新評論