最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

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

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

spring三級(jí)緩存的解讀

spring 中為了解決 B的重復(fù)利用,A 依賴B 的循環(huán)依賴,aop 問(wèn)題,多線程可能拿到不完整的bean 的問(wèn)題引入了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 實(shí)例
  • earlySingletonObjects 用于存放早期的bean 實(shí)例
  • singletonFactories 用于存放簡(jiǎn)單工廠實(shí)例

從3級(jí)緩存中 獲取bean 的方法有如下兩個(gè)

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

protected Object getSingleton(String beanName, boolean allowEarlyReference) {
   // 這里不用考慮指令重排,因?yàn)?bean 初始化完成后才會(huì)放入map
   Object singletonObject = this.singletonObjects.get(beanName);
   if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
      // 加鎖,與另一個(gè)getSingleton 方法 互斥訪問(wèn),保證并發(fā)情況下獲取到不完整的bean
      synchronized (this.singletonObjects) {
         singletonObject = this.earlySingletonObjects.get(beanName);
         if (singletonObject == null && allowEarlyReference) {
            // 獲取工廠bean ,因?yàn)榭赡苁莂op 生成的代理,這里二級(jí)和三級(jí)緩存保證獲取到的bean 是最后的完整bean
            ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
            if (singletonFactory != null) {
               singletonObject = singletonFactory.getObject();
               // 放入 二級(jí)緩存中,從3級(jí)緩存中移除
               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) {
      // 再次從一級(jí)緩存中獲取,因?yàn)槎嗑€程加載同一個(gè)bean 時(shí),
      //相當(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 與多線程競(jìng)爭(zhēng)的情況,此時(shí)我們只需要一級(jí)緩存就可以解決循環(huán)依賴的問(wè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且不考慮多線程的情況下,只要一個(gè)map1 我們就能解決循環(huán)依賴的問(wèn)題

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

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

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

可以對(duì)是否aop 代理過(guò)存儲(chǔ)一個(gè)標(biāo)志位,此時(shí)必然在后面獲取bean 的時(shí)候都要多一層判斷,所以此時(shí)需要二層緩存來(lái)解決

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

4.我們?cè)倏紤]并發(fā)的情況,即多線程獲取一個(gè)單例

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

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

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

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

總結(jié)

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

相關(guān)文章

  • 23種設(shè)計(jì)模式(8) java外觀模式

    23種設(shè)計(jì)模式(8) java外觀模式

    這篇文章主要為大家詳細(xì)介紹了23種設(shè)計(jì)模式之java外觀模式,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-11-11
  • Spring中屬性注入的幾種方式以及復(fù)雜屬性的注入詳解

    Spring中屬性注入的幾種方式以及復(fù)雜屬性的注入詳解

    這篇文章主要介紹了Spring中屬性注入的幾種方式以及復(fù)雜屬性的注入詳解,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-04-04
  • 數(shù)據(jù)庫(kù)基本操作語(yǔ)法歸納總結(jié)

    數(shù)據(jù)庫(kù)基本操作語(yǔ)法歸納總結(jié)

    本篇文章主要介紹了數(shù)據(jù)庫(kù)的一些常用方法及一些基本操作,需要的朋友可以參考下
    2017-04-04
  • Java中包裝類和Arrays類的詳細(xì)介紹

    Java中包裝類和Arrays類的詳細(xì)介紹

    Arrays針對(duì)于數(shù)組做操作的類,該類包含用于操作數(shù)組的各種方法(如排序和搜索),這篇文章主要給大家介紹了關(guān)于Java中包裝類和Arrays類的詳細(xì)介紹,文中通過(guò)實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2022-12-12
  • java計(jì)算任意位水仙花數(shù)示例(回文數(shù))

    java計(jì)算任意位水仙花數(shù)示例(回文數(shù))

    這篇文章主要介紹了java計(jì)算任意位水仙花數(shù)示例(回文數(shù)),需要的朋友可以參考下
    2014-05-05
  • Java cookie和session會(huì)話技術(shù)介紹

    Java cookie和session會(huì)話技術(shù)介紹

    session的工作原理和cookie非常類似,在cookie中存放一個(gè)sessionID,真實(shí)的數(shù)據(jù)存放在服務(wù)器端,客戶端每次發(fā)送請(qǐng)求的時(shí)候帶上sessionID,服務(wù)端根據(jù)sessionID進(jìn)行數(shù)據(jù)的響應(yīng)
    2023-04-04
  • 五分鐘帶你快速學(xué)習(xí)Spring?IOC

    五分鐘帶你快速學(xué)習(xí)Spring?IOC

    這篇文章主要給大家介紹了關(guān)于如何通過(guò)五分鐘快速學(xué)習(xí)Spring?IOC的相關(guān)資料,文中通過(guò)實(shí)例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2022-03-03
  • Flutter實(shí)現(xiàn)文本組件、圖標(biāo)及按鈕組件的代碼

    Flutter實(shí)現(xiàn)文本組件、圖標(biāo)及按鈕組件的代碼

    這篇文章主要介紹了Flutter實(shí)現(xiàn)文本組件、圖標(biāo)及按鈕組件的代碼,本文給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值 ,需要的朋友可以參考下
    2019-07-07
  • java的java.security.egd源碼解讀

    java的java.security.egd源碼解讀

    這篇文章主要為大家介紹了java的java.security.egd源碼解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-08-08
  • Java面試最容易被刷的重難點(diǎn)之鎖的使用策略

    Java面試最容易被刷的重難點(diǎn)之鎖的使用策略

    鎖像synchronized同步塊一樣,是一種線程同步機(jī)制,但比Java中的synchronized同步塊更復(fù)雜。因?yàn)殒i(以及其它更高級(jí)的線程同步機(jī)制)是由synchronized同步塊的方式實(shí)現(xiàn)的,所以我們還不能完全擺脫synchronized關(guān)鍵字
    2021-10-10

最新評(píng)論

砀山县| 仁布县| 连平县| 基隆市| 都昌县| 兰考县| 衡阳市| 古丈县| 新野县| 东安县| 平潭县| 方山县| 鄂托克旗| 扶余县| 崇礼县| 肇庆市| 商水县| 胶州市| 开封市| 北川| 贵南县| 平凉市| 清远市| 稷山县| 安顺市| 舒兰市| 河池市| 甘谷县| 临澧县| 湘西| 商丘市| 金昌市| 湖南省| 邵武市| 阳原县| 滁州市| 双江| 龙泉市| 汶上县| 台北市| 昌江|