日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 前端技术 > javascript >内容正文

javascript

Spring Boot————默认缓存应用及原理

發布時間:2025/3/12 javascript 19 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Spring Boot————默认缓存应用及原理 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

引言

應用程序的數據除了可以放在配置文件中、數據庫中以外,還會有相當一部分存儲在計算機的內存中,這部分數據訪問速度要快于數據庫的訪問,因此通常在做提升數據訪問速度時,會將需要提升訪問速度的數據放入到內存中,我們稱之為緩存

最常用的緩存方式是使用并發容器,因為具有比較高的并發性能,因此Spring的默認緩存策略就是使用ConcurrentHashMap作為緩存容器。下面將會逐步展開緩存的概念與Spring中的使用規則。

一、JSR-107緩存API

為了統一緩存的開發規范,以及提升系統的擴展性,J2EE發布了JSR-107緩存規范。主要定義了五大核心接口:

CachingProvider、CacheManager、Cache、Entry、Expiry

而實際開發中,我們通常會使用Spring緩存抽象來完成對緩存的操作,它是Spring為開發者定義的一套用于管理緩存的接口及相關實現。而Spring緩存抽象底層的概念與這五大接口的描述都是通用的,因此了解JSR-107定義的相關概念以及API接口描述,將有助于我們學習Spring的緩存抽象。

1.1 接口定義

1、CachingProvider:定義了創建、配置、獲取、管理和控制多個CacheManager。一個應用可以在運行期訪問多個CachingProvider。

2、CacheManager定義了創建、配置、獲取、管理和控制多個唯一命名的Cache,這些Cache存在于CacheManager的上下文中。一個CacheManager僅被一個CachingProvider所擁有。

3、Cache:這是一個類似Map的數據結構并臨時存儲以Key為索引的值。一個Cache僅被一個CacheManager所擁有。

4、Entry:它是一個存儲在Cache中的Key-Value對。

5、Expiry:每一個存儲在Cache中的條目都有一個定義的有效期。一旦超過這個時間,條目為過期的狀態。一旦過期,條目將不可訪問、更新、刪除。緩存有效期可以通過ExpiryPolicy設置。

1.2 接口關系圖譜

二、Spring緩存抽象(以下重點)

2.1 Spring緩存接口

Spring從3.1開始定義了:org.springframework.cache.Cache?和 org.springframework.cache.CacheManager?接口來統一不同的緩存技術,并支持使用JCache(JSR-107)注解簡化我們的開發。那么按照JSR-107的緩存思想,CacheManager就是用于管理Cache的,而Cache則是真正對緩存進行操作的抽象。

1、Cache接口是具體的緩存組件的規范定義,包含對緩存數據的各種操作;

2、Cache接口下Spring提供了各種xxxCache組件(實現類),如RedisCache,EhCacheCache,ConcurrentMapCache等。

每次調用需要緩存功能的方法時,Spring都會檢查指定參數的指定目標方法是否已經被調用過。如果有就直接從緩存中獲取方法調用后的結果;如果沒有就調用方法并緩存結果后返回給用戶,下次調用直接從緩存中獲取。

使用Spring緩存抽象時我們需要注意以下兩點:

1、確定哪些方法需要被緩存以及它們的緩存策略。

2、從緩存中讀取之前緩存存儲的數據。

2.2 Spring 緩存注解

最常用的緩存注解有如下:

@Cacheable主要針對方法配置,能夠根據方法的請求參數對其結果進行緩存。

@CacheEvict清空緩存。用于標注在一些刪除方法上。

@CachePut保證方法被調用,又希望結果被緩存。用于標注在一些更新方法上,更新緩存。

@EnableCaching開啟基于注解的緩存。

2.3 緩存策略

keyGengerator緩存數據時key的生成策略。

serialize緩存數據時value的序列化策略。

三、Spring緩存快速入門

自進入Spring Boot時代,很多功能都已經不再需要繁雜的Java代碼來實現,而是使用注解來完成相同的功能,下面將介紹如何使用注解的方式來完成一整套關于Spring默認緩存數據的操作。

3.1 開啟基于注解的緩存功能

首先,如果希望使用注解的方式使用緩存,那么就需要開啟基于注解的緩存功能。

具體方法是在Spring Boot的主程序上加上@EnableCaching注解:

@EnableJpaRepositories @SpringBootApplication @EnableCaching public class CourseSystemApplication {public static void main(String[] args) {SpringApplication.run(CourseSystemApplication.class, args);} }

3.2 自定義緩存組件

CacheManager管理多個Cache組件,對緩存的真正CRUD操作在Cache組件中,每一個緩存組件有自己唯一一個名字。因此,在使用注解定義緩存組件的時候需要指定一些屬性:

cacheNames?/ value:指定緩存組件的名稱,兩個屬性都是指定緩存名稱,二選一。

key:緩存數據使用的key。默認是使用方法參數的值。而緩存的數據就是方法返回值。另外key也可以使用SpEL表達式來表示。

keyGenerator:key的生成器,與key屬性二選一。

cacheManager:指定緩存管理器,或者cacheResolver指定緩存解析器。

condition:指定符合條件的情況下才緩存。

unless:否定緩存。當unless指定的條件為true,方法返回值就不會緩存。也可以獲取到結果判斷是否需要緩存,如:? ? ? ? unless = “#result == null”,就代表如果結果是null就不緩存。

sync:是否使用異步模式進行緩存。注意!!sync屬性默認為false,如果為true,則unless屬性將不再支持

附?SpEL表達式指定key的規則?:

3.3 代碼示例

在查詢全部課程的serviceImpl方法上使用緩存注解@Cacheable。

@Cacheable(cacheNames?=?"courses")?? public?List<Course>?findAllCourses()?{??List<Course>?allCourses?=?couseRep.findAll();??logger.info("查詢全部課程?:?"?+?allCourses);??return?allCourses; }

查詢效果 :?

第一次查詢,有SQL日志打印;第二次以后都沒有SQL打印,說明緩存生效了

問題描述?

1、第一次在Service接口中標記了緩存注解,沒有生效。原因很可能是因為當service組件自動注入的時候實則是實現類在真正執行操作,因此,只有在真正使用的組件上使用緩存才能夠起作用。因此,以interface--Impl的形式開發的時候,要將緩存注解標記在具體實現類上,否則會失效。

2、給key屬性賦值一個普通的字符串,報:SpelEvaluationException異常。因此這個key只能使用SpEl表達式來描述。像上面這種沒有參數的情況,可以不必指定key屬性,spring會默認為緩存數據生成一個key。

四、@Cacheable緩存工作原理

4.1 緩存組件的自動配置

緩存的相關配置來自于CacheAutoConfiguration類。

這個類使用@Import注解向容器中導入一個CacheConfigurationImportSelector的靜態內部類,和其他自動配置時的導入選擇器類似,它也是ImportSelector的實現類,這些實現類只有一個方法:String[] selectImports(...),專門用來導入具體的JavaConfig配置類。

而CacheConfigurationImportSelector,負責導入各種緩存組件的配置類。通過在selectImports內部打上斷點debug啟動項目的方式,我們可以一覽返回值String[]中的內容:

[??org.springframework.boot.autoconfigure.cache.GenericCacheConfiguration,???org.springframework.boot.autoconfigure.cache.JCacheCacheConfiguration,???org.springframework.boot.autoconfigure.cache.EhCacheCacheConfiguration,???org.springframework.boot.autoconfigure.cache.HazelcastCacheConfiguration,???org.springframework.boot.autoconfigure.cache.InfinispanCacheConfiguration,???org.springframework.boot.autoconfigure.cache.CouchbaseCacheConfiguration,???org.springframework.boot.autoconfigure.cache.RedisCacheConfiguration,???org.springframework.boot.autoconfigure.cache.CaffeineCacheConfiguration,???org.springframework.boot.autoconfigure.cache.GuavaCacheConfiguration,???org.springframework.boot.autoconfigure.cache.SimpleCacheConfiguration,???org.springframework.boot.autoconfigure.cache.NoOpCacheConfiguration?? ]

這些緩存配置,就是Spring緩存抽象的具體底層實現所需要用到的JavaConfig。

這些配置類內部都會有一些規則判斷,@ConditionalXxx來判斷是否生效。以第一個GenericCacheConfiguration為例:

@Configuration @ConditionalOnBean(Cache.class) @ConditionalOnMissingBean(CacheManager.class) @Conditional(CacheCondition.class) class GenericCacheConfiguration {private final CacheManagerCustomizers customizers;GenericCacheConfiguration(CacheManagerCustomizers customizers) {this.customizers = customizers;}@Beanpublic SimpleCacheManager cacheManager(Collection<Cache> caches) {SimpleCacheManager cacheManager = new SimpleCacheManager();cacheManager.setCaches(caches);return this.customizers.customize(cacheManager);} }

可以看到類頭上,相關的@Conditional注解來表明這個配置類在哪種情況下生效。但是我們也可以使用spring boot的自動配置報告來查看究竟是哪個緩存配置類生效。

4.2?SimpleCacheConfiguration

通過在全局配置文件中設置debug=true,使用spring boot的自動配置報告功能,打印匹配的JavaConfig配置類,我們可以看到默認啟用的緩存配置是SimpleCacheConfiguration

打開這個配置類:

/*** Simplest cache configuration, usually used as a fallback.** @author Stephane Nicoll* @since 1.3.0*/ @Configuration @ConditionalOnMissingBean(CacheManager.class) @Conditional(CacheCondition.class) class SimpleCacheConfiguration {private final CacheProperties cacheProperties;private final CacheManagerCustomizers customizerInvoker;SimpleCacheConfiguration(CacheProperties cacheProperties,CacheManagerCustomizers customizerInvoker) {this.cacheProperties = cacheProperties;this.customizerInvoker = customizerInvoker;}@Beanpublic ConcurrentMapCacheManager cacheManager() {ConcurrentMapCacheManager cacheManager = new ConcurrentMapCacheManager();List<String> cacheNames = this.cacheProperties.getCacheNames();if (!cacheNames.isEmpty()) {cacheManager.setCacheNames(cacheNames);}return this.customizerInvoker.customize(cacheManager);} }

這個配置類通過@Bean向容器中注冊了一個ConcurrentMapCacheManager對象,這個CacheManager可以獲取和創建ConcurrentMapCache類型的緩存組件。

4.3 緩存執行流程(重點)

使用@Cacheable時:

1、在方法service方法第一次執行前,先去查詢Cache(緩存組件)。它是按照cacheNames指定的名字調用CacheManager中的getCache(String name)方法獲取的。

@Override 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; }

當第一次執行時未找到指定緩存,那么就會去調用createConcurrentMapCache(name)創建這個緩存,并將key-value放入到緩存中。

2、去Cache中查找緩存,使用一個key,這個key默認是使用SimpleKeyGenerator生成key。

SimpleKeyGengerator生成key的默認策略:

/*** Generate a key based on the specified parameters.*/ public static Object generateKey(Object... params) {if (params.length == 0) {return SimpleKey.EMPTY;}if (params.length == 1) {Object param = params[0];if (param != null && !param.getClass().isArray()) {return param;}}return new SimpleKey(params); }

如果沒有參數,那么key就是用一個SimpleKey對象;如果有一個參數,則key = 參數的值;

如果有多個參數,key = new SimpleKey(params);

3、沒有查找到緩存就調用目標方法。

4、將目標方法返回的結果,放入緩存中。

總結?

由@Cacheable標注的方法執行之前先來檢查緩存中有沒有這個數據,默認按照參數的值作為key去查詢,如果沒有就運行方法,并將結果放入緩存,以后再調用就可以直接是用緩存中的數據。

核心

1、是用CacheManager(默認ConcurrentMapCacheManager)按照名字得到Cache(默認ConcurrentMapCache)組件。

2、key使用keyGenerator生成的,默認的是SimpleKeyGenerator

五、自定義keyGenerator

自定義的key有兩種實現手段,一種是通過@Cacheable的key屬性,另一個是通過keyGenerator屬性。

key屬性使用的是SpEL表達式來指定key的格式規則,如:key = “#root.methodName+’[’+#id+’]’”,但是一種比較零散的自定義策略。

而keyGenerator可以指定一個通用的緩存key的生成策略。在這里簡單說一下代碼實現。

@Configuration public class SysCacheKeyGenerator {/*** 課程緩存key生成策略*/@Bean("courseDefaultKeyGenerator")public KeyGenerator courseCacheKeyGenerator() {return new KeyGenerator() {@Overridepublic Object generate(Object target, Method method, Object... params) {String key = params.length == 0 ? "courseList" : params.toString();return method.getName() + "." + key;}};} }

使用這段代碼來定義一個自定義的keyGenerator,并注冊到容器中,然后配置@Cacheable的keyGenerator屬性:

@Override @Cacheable(cacheNames = "courses", keyGenerator = "courseDefaultKeyGenerator") public List<Course> findAllCourses() {List<Course> allCourses = couseRep.findAll();logger.info("查詢全部課程 : " + allCourses);return allCourses; }

那么實際緩存時就會使用我們自定義的key:

六、設置緩存條件

@Cacheable注解,

condition屬性可以動態的判斷數據是否滿足緩存條件。

如:condition = “#id > 1”,意思是判斷參數id的值大于1的情況下才對結果緩存。

那么它的用法主要依賴于SpEl表達式的邏輯判斷。

unless屬性的意思是“不緩存”,同樣是通過SpEl表達式來判斷true或false,如果unless的條件成立,那么將不會對數據進行緩存。

如:unless = “#id == 2”?,意思是如果id的值為2,那么就不緩存結果了。

七、@CachePut

@CachePut注解意為更新緩存。

一般標注在涉及到數據庫更新操作的方法上,在更新數據庫中記錄的同時也會更新緩存中對應的數據。

運行實際

1、先調用目標方法

2、將目標方法的結果緩存起來。

注意 !!!

在使用@CachePut的時候要注意緩存數據的key要與查詢該緩存數據時所用的key保持一致,否則,兩個key如果不一致,就會出現查詢方法依然是緩存更新之前的數據。

這里key可以使用#result來取得返回結果,及其內部屬性如#result.id,但是@Cacheable不能使用#result來取得結果值,想想這是為什么?(提示,執行時機)

八、@CacheEvict

@CacheEvict :清除緩存。

key:指定要清除的緩存。

allEntries = true 代表清除這個緩存中的所有數據。

beforeInvocation = false 代表清除緩存的操作是在方法執行后,這也是默認值。如果出現異常,那么就不會清除緩存。該屬性如果為true,那么就代表在方法執行前清除緩存,無論方法是否出現異常。

九、@Caching與@CacheConfig

@Caching是一個復雜緩存的注解,可以指定多種緩存規則;@CacheConfig放在類頭上,用于抽取一些公共的緩存屬性配置,如可以指定公共的緩存名稱。

總結

關于Spring默認緩存組件的使用,基本就是@Cacheable、@CachePut、@CacheEvict這三個注解,另外注意在使用它們之前,記得在Spring Boot的程序主類上開啟@EnableCaching。

另外,一定要注意@Cacheable和@CachePut的執行時機,以及它們真正操作的key值,因為這個緩存數據是存儲在內存中的,因此不像數據庫中的數據那樣直觀明了,操作緩存中的數據要求開發者有比較好的數據管理規則,否則,很容易出現緩存數據失效的問題。

綜上,就是關于Spring Boot使用默認緩存管理器的緩存數據的基本操作方法和基本工作原理,歡迎文末留言。

總結

以上是生活随笔為你收集整理的Spring Boot————默认缓存应用及原理的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。