<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          SpringBootCache源碼解析:默認Cache配置

          共 7131字,需瀏覽 15分鐘

           ·

          2022-04-25 07:52


          默認 Cache 配置

          當使用@EnableCachina 啟動 Spring Boot 的緩存機制但又未添加其他緩存類庫時,SpringBoot 會默認提供一個基 于 ConcurrentHashMap 實現(xiàn)的緩存組件
          --ConcurrentMap-CacheManager。但官方文檔已經(jīng)明確提示,不建議在生產(chǎn)環(huán)境中使用該緩存組件。但它卻是一個很好的學習緩存特性的工具。

          這個默認的緩存組件是通過 SimpleCacheConfiguration 來完成自動配置的。下面,我們簡單了解一下它的自動配置以及 ConcurrentMapCacheManager 的實現(xiàn)。

          @Configuration(proxyBeanMethods = false)
          @ConditionalOnMissingBean(CacheManager.class)
          @Conditional(CacheCondition. class)
          class SimpleCacheConfiguration {
          @Bean
          ConcurrentMapCacheManager cacheManager(CacheProperties cacheProperties,
          CacheManagerCustomizers cacheManagerCustomizers) {
          ConcurrentMapCacheManager cacheManager = new ConcurrentMapCacheManager
          ();
          List cacheNames = cacheProperties . getCacheNames();
          if (!cacheNames. isEmpty()) {
          cacheManager . setCacheNames (cacheNames);
          }
          return cacheManagerCustomizers . customize(cacheManager);}
          }

          該 自 動 配 置 文 件 很 簡 單 , 當 容 器 中 不 存 在 CacheManager 的 Bean, 同 時 滿 足CacheCondition 中指定的條件時,則進行自動配置。關(guān)于 CacheCondition 中的業(yè)務(wù)邏輯實現(xiàn)已經(jīng)在上一節(jié)進行了詳細地講解,不再贅述。

          在 cacheManager 方法中首先創(chuàng)建了- -個 ConcurrentMapCacheManager 對象,然后通過配置屬性類獲得緩存名稱列表,如果列表內(nèi)容不為空,則賦值給上述對象 cacheManager。

          最后調(diào)用 CacheManagerCustomizers 的 customize 方法對 cacheManager 進行定制化處理并返回。

          下面我們重點看 cacheManager 方法中 ConcurrentMapCacheManager 類的內(nèi)部實現(xiàn)。通過名字就可以看出它是基于 ConcurrentHashMap 來實現(xiàn)的,它是接口 CacheManager 的實現(xiàn)類,同時也實現(xiàn)了 BeanClassLoaderAware 接口用來獲取 SerializationDelegate 及進行一些初始化操作。


          首先看 ConcurrentMapCacheManager 的成員變量部分源代碼。

          public class ConcurrentMapCacheManager implements CacheManager, BeanClassLo
          aderAware
          {
          // ConcurrentMapCacheManager 緩存的基礎(chǔ)數(shù)據(jù)結(jié)構(gòu),用于存儲緩存數(shù)據(jù) private final
          ConcurrentMap cacheMap = new ConcurrentHashMap<>(16);
          //是否為動態(tài)創(chuàng)建緩存
          private boolean dynamic = true;
          //是否允許 null 值
          private boolean allowNullValues = true;
          //是否存儲 value 值
          private boolean storeByValue = false;
          //用于序列化的委托類,通過實現(xiàn) BeanClassLoaderAware 接口注入,用子值的序列化和反
          序列號
          @Nullable
          private SerializationDelegate serialization;
          }

          在 ConcurrentMapCacheManager 中定義了 ConcurrentMap的成員變量,用于存儲 Cache,無論后面是獲取還是存儲緩存類(Cache) ,都圍繞該成員變量來進行操作。

          這里采用的 ConcurrentHashMap 是 Java 中的一個線程安全且高效的 HashMap 實現(xiàn)。

          dynamic 屬性定義了緩存是動態(tài)創(chuàng)建還是靜態(tài)創(chuàng)建,true 表示動態(tài)創(chuàng)建 ,false 表示靜態(tài)創(chuàng)建,后面在涉及具體的方法功能時會用到; allowNullValues 用來表示是否允許 nul 值;

          storeByValue 表示是否需要存儲值, 如果需要存儲值則需配合 serialization 順序性進行序列化和反序列號操作。這里的存儲值指的是復制的 value 值,與存儲引用相對,存儲值(復制的 value 值)時才會進行序列化和反序列化。


          下面從 ConcurrentMapCacheManager 的構(gòu)造方法開始來進行相關(guān)方法的講解。

          public class ConcurrentMapCacheManager implements CacheManager, BeanClassLoaderAware.
          //實現(xiàn)為空的構(gòu)造方法,用于構(gòu)建.
          動態(tài)的 ConcurrentMapCacheManager,
          //當緩存實例被請求時進行懶加裁
          public ConcurrentMapCacheManager() {
          //構(gòu)建一個靜態(tài)的 ConcurrentMapCacheManager, 僅管理捐定緩存名稱的緩存
          public ConcurrentMapCacheManager(Stri
          , cacheNames) {
          setCacheNames (Arrays . aslist(cacheNames));
          /設(shè)置緩存名稱或重置緩存模式
          public void setCacheNames (@Nullable Collection cacheNames) {
          if (cacheNames != null)
          for (String name : cacheNames){
          this . cacheMap. put(name, createConcurrentMapCache(name));
          this.dynamic = false;
          } else
          this . dynamic = true;
          }
          }
          }

          ConcurrentMapCacheManager 提供了兩個構(gòu)造方法,第一-個構(gòu)造方法用于構(gòu)建一個動態(tài)的 ConcurrentMapCacheManager, 構(gòu)造方法實現(xiàn)為空。在自動配置中便是采用的該構(gòu)造方法,默認情況下,dynamic 屬 性的為 true,即動態(tài)構(gòu)建,當緩存實例被請求時進行懶加載。

          另外一個構(gòu)造方法的參數(shù)為不定參數(shù),構(gòu)造方法內(nèi)的核心操作就是調(diào)用 setCacheNames 方法。在 setCacheNames 方法內(nèi)部, 如果 cacheNames 不為 null,也就是采用“靜態(tài)”模式,會遍歷緩存名稱,并初始化 cacheMap 中的值。這里需要注意的是,一旦進入該業(yè)務(wù)邏輯操作,也就意味著緩存的屬性及名稱將被固定,運行時不會再創(chuàng)建其他緩存區(qū)域。

          那么,如果想改變這種“不變"的情況該如何處理?還是調(diào)用該方法,設(shè)置參數(shù) cacheNames為 null,此時執(zhí)行 else 中的邏輯,將 dynamic 設(shè)置 為 true,即靜態(tài)模式重置為動態(tài)模式,從而允許再次創(chuàng)建緩存區(qū)域。setCacheNames 方法為 public,因此不僅構(gòu)造方法可以調(diào)用,其實例化對象也可以直接調(diào)用進行設(shè)置。

          在第二個構(gòu)造方法中調(diào)用了當前類的 createConcurrentMapCache 方法,代碼如下。

          protected Cache createConcurrentMapCache(String name) {
          SerializationDelegate actualSerialization = (isStoreByValue() ? this.seri
          alization : null);
          return new ConcurrentMapCache(name, new ConcurrentHashMap<> (256),
          isAllowNullValues(),actualSerialization);
          }

          createConcurrentMapCache 方法的主要作用就是創(chuàng)建一個 ConcurrentMapCache,它是Cache 接口的簡單實現(xiàn)。該方法內(nèi),首先根據(jù)屬性 storeByValue 的值判斷是否需要Serializa-tionDelegate 來進行序列化操作,如果不需要則將 SerializationDelegate 設(shè)置為null。然后,將緩存名稱、緩存值、是否允許 Nul1 值和序列化委托類當作構(gòu)造參數(shù)創(chuàng)建Concurrent-MapCache 類并返回。

          在 ConcurrentMapCacheManager 中有-個私有的 recreateCaches 方法,在滿足條件的情況下會遍歷 cacheMap 并調(diào)用上面 createConcurrentMapCache 方法進行緩存的重置操作。

          private void recreateCaches() {
          for (Map. Entry entry : this. cacheMap .entrySet()) {
          entry . setValue(createConcurrentMapCache(entry . getKey()));
          }

          當 allowNullValues 或 storeByValue 的值通過 set 方法改變時,均會調(diào)用 recreateCaches方法進行緩存的重置。

          最后看 ConcurrentMapCacheManager 對 getCacheNames 和 getCache 方法的實現(xiàn)。

          @Override
          public Collection getCacheNames() {
          return Collections . unmodifiableSet(this . cacheMap. keySet());
          @Override
          @Nullable
          public Cache getCache(String name) {
          Cache cache = this. cacheMap . get(name);
          if (cache == null && this. dynamic) {
          synchronized (this . cacheMap) {cache = this. cacheMap . get(name);
          if (cache == null) {
          cache = createConcurrentMapCache(name);
          this. cacheMap . put(name, cache);
          }
          }
          }
          return cache; }

          getCacheNames 方法直接獲取 cacheMap 中 name 的 Set,并通過 Collections 類將其設(shè)置為不可變的集合并返回。

          getCache 方法首先根據(jù) name 從 cacheMap 中獲取 Cache 值,如果值為 null 并且是動態(tài)模式,則對 cacheMap 加鎖同步, 重新獲取判斷,如果 cache 依舊為 null,則調(diào)用create-ConcurrentMapCache 方 法創(chuàng)建并給 cacheMap 賦值。否則,直接返回 cache 值。

          至此,關(guān)于 ConcurrentMapCacheManager 的基本功能也講解完畢。在此提醒一下,這只是一一個簡單的 CacheManager,并沒有緩存配置項,僅可用于測試環(huán)境和簡單的緩存場景。

          對于高級的本地緩存需求建議使用 JCacheCacheManager、EhCacheCacheManager、CaffeineCacheManager 等方法。

          最后,我們再稍微拓展一下上面提到的 ConcurrentMapCache 類,該類實現(xiàn)了 Cache 接口,提供了緩存值的存儲和獲取等實現(xiàn)。而這些功能的實現(xiàn)就是圍繞上面提到構(gòu)造該類時傳入的參數(shù)展開的。

          以 ConcurrentMapCache 的 put 方法及相關(guān)方法為例,我們簡單說一下它的實現(xiàn)過程。

          @Override
          public void put(0bject key, @Nullable object value) {
          this . store. put(key, toStoreValue(value));
          @Override
          protected object toStoreValue (@Nullable object userValue) {
          //父類的 toStoreValue 方法實現(xiàn),用于檢查是否允許 null。如果值為 null 且允許為 null,則返
          @NullValue.
          INSTANCE
          Object storeValue = super . toStoreValue(userValue);
          if (this. serialization != null) {
          try {
          //對質(zhì)進行序列化
          return serializeValue(this . serialization, storeValue);
          catch (Throwable ex) {throw new IllegalArgumentException("Failed to serialize cache valueuserValue +
          "
          '. Does it implement Serializabl
          e?", ex);
          } else {
          return storeValue;
          //通過傳入的 Serial izationDelegate 序列化緩存值為 byte 數(shù)組
          private object serializeValue(SerializationDelegate serialization, object s
          toreValue) throws IOException {
          ByteArrayOutputStream out = new ByteArrayOutputStream();
          try {
          serialization. serialize(storeValue, out);
          return out. toByteArray();
          } finally {
          out. close();
          }

          上面為 put 方法涉及的操作,基本步驟是如下。

          .判斷待設(shè)置的 userValue 的值是否為 mull,如果為 mull 且允許存儲 mull 值,返回NullValue.INSTANCE。否則,直接返回 userValue 值。以上值均賦值給 storeValue。

          如果序列化委托類(serialization )不為 null, 則通過 SerializationDelegate 對 storeValue 值進行序列化操作。如果為 mull,則直接返回 store Value。

          .無論經(jīng)過以上步驟獲得的是原始傳入值、NullValue.INSTANCE 或是經(jīng)過序列化的字節(jié)數(shù)組 , 都 通 過 store 的 put 方 法 將 其 存 儲 。store 的數(shù) 據(jù) 結(jié) 構(gòu) 為Concurrent-Map,就是我們創(chuàng)建 ConcurrentMapCache 時傳入的參數(shù)之一。

          其中第一個 Object 為緩存的 key,第二個 Object 為緩存的具體數(shù)據(jù)。

          至此,Spring Boot 默認,的。Cache 配置就講解完畢了,關(guān)于滾動鼠標軸或單擊,開始截長圖 ConcurrentMapCache 類的其他方法實現(xiàn),讀者朋友可自行閱讀相關(guān)源碼,不過基本上都是圍繞上面提到的一-些屬性和數(shù)據(jù)結(jié)構(gòu)展開的。


          小結(jié)

          本章重點介紹了 Spring Boot 中緩存的自動配置以及基于 ConcurrentHashMap 實現(xiàn)的最簡單 的 緩 存 功 能 。涉 及 的 緩 存 實 現(xiàn) 都 只 是 基 于 Java 提 供 的 數(shù) 據(jù) 結(jié) 構(gòu) (Collection 、ConcurrentHashMap) 存儲來實現(xiàn)的。而在實戰(zhàn)過程中,根據(jù)不同的場景會使用不同的三方緩存組件,比如 JCache、EhCache、Caffeine、 Redis 等。但基本的實現(xiàn)原理一致,讀者朋友可參照本章內(nèi)容進行具體的分析學習。

          本文給大家講解的內(nèi)容是SpringBootCache源碼解析:默認Cache配置

          1. 下篇文章給大家講解的是Spring Boot 日志源碼解析;

          2. 覺得文章不錯的朋友可以轉(zhuǎn)發(fā)此文關(guān)注小編;

          3. 感謝大家的支持!


          本文就是愿天堂沒有BUG給大家分享的內(nèi)容,大家有收獲的話可以分享下,想學習更多的話可以到微信公眾號里找我,我等你哦。

          瀏覽 38
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  久久中文综合 | 亚洲成人免费视频 | 中国A片乱子伦 | 在线看黄wwww | 韩国三级中文字幕HD久久精品 |