Spring Cache的使用示例詳解
1. 使用入門
1. 添加依賴
在spring boot中使用Spring Caching需要先引入依賴:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cache</artifactId>
<version>3.1.5</version>
</dependency>Spring Caching是構建在Spring Context的基礎上的,如果原先沒有它的引用的話,需要添加對應的依賴
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>6.0.13</version>
</dependency>Spring Context Support里提供了EhCache和Caffeine的CacheManager抽象,如果你打算用這兩個緩存實現(xiàn)的話,還有依賴
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
<version>6.0.13</version>
</dependency>2. 啟用緩存
在已經(jīng)添加了spring-boot-starter-cache的前提下,只需要使用@EnableCaching注解,Spring會默認創(chuàng)建一個ConcurrentMapCacheManager負責緩存,不過它并不支持緩存過期。 除此以外,我們也可以手動創(chuàng)建CacheManager
@Configuration
@EnableCaching
public class CachingConfig {
@Bean
public CacheManager cacheManager() {
return new ConcurrentMapCacheManager("users");
}
}3. 集成EhCache
添加EhCache的依賴
<!-- Ehcache -->
<dependency>
<groupId>org.ehcache</groupId>
<artifactId>ehcache</artifactId>
</dependency>
<!-- Spring Integration for Ehcache -->
<dependency>
<groupId>javax.cache</groupId>
<artifactId>cache-api</artifactId>
</dependency>
<dependency>
<groupId>org.ehcache</groupId>
<artifactId>ehcache-jsr107</artifactId>
</dependency>在src/main/resources創(chuàng)建配置文件ehcache.xml
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="http://ehcache.org/ehcache.xsd">
<cache name="card:id"
maxEntriesLocalHeap="1000"
eternal="false"
timeToIdleSeconds="10"
timeToLiveSeconds="30"
memoryStoreEvictionPolicy="LRU"/>
</ehcache>4. @Cachable
這是最常用的注解,如果緩存中存在,返回緩存中的數(shù)據(jù),否則調(diào)用方法計算,并將結(jié)果寫入緩存
@Cacheable("card:id")
public String getCardById(Long id) {...}添加了這個注解,相當于執(zhí)行偽代碼
String data = cacheManager.get(cacheKey)
if(data == null) {
data = getCardById(id)
cacheManager.put(cacheKey, data)
}
return cached;@Cachable還有一個sync屬性,設置為true時會對緩存加載用cacheKey做同步,如果加了注解@Cacheable("card:id", sync=true)的話,偽代碼如下
String data = cacheManager.get(cacheKey)
if(data == null) {
synchronized(cacheKey) {
data = cacheManager.get(cacheKey);
if(data == null) {
data = getCardById(id)
cacheManager.put(cacheKey, data)
}
}
}
return cached;關于cacheKey的生成邏輯,見后續(xù)章節(jié)。
5. @CacheEvict
用于從緩存中刪除數(shù)據(jù),假設我們有一個更新card的接口,調(diào)用會清除card:id下的所有緩存。
@CacheEvict(value="card:id", allEntries=true)
public String updateCardById(Long cardId, Customer customer) {...}我們可以可以清除指定key的數(shù)據(jù),key用SpEL來計算
@CacheEvict(value="card:id",, key = "'card_' + #cardId")
public String updateCardById(Long cardId, Customer customer) {...}6. @CachePut
用于更新緩存數(shù)據(jù),想@Cacheable的區(qū)別是,它不會檢查緩存中是否有數(shù)據(jù),始終都調(diào)用方法獲取數(shù)據(jù),并更新緩存。
@CachePut("card:id")
public String getCardById(Long id) {...}7. @Caching
用在一個方法上有多個緩存操作的時候,比如
@Caching(evict = {
@CacheEvict("addresses"),
@CacheEvict(value="directory", key="#customer.name") })
public String getAddress(Customer customer) {...}8. @CacheConfig
用于設置service級別的緩存配置,比如CustomerDataService的方法都操作addresses這個緩存,可以這么配置
@CacheConfig(cacheNames={"addresses"})
public class CustomerDataService {
@Cacheable
public String getAddress(Customer customer) {...}
}9. condition/unless
基于條件的緩存,condition基于入?yún)⑴袛啵瑄nless基于返回值判斷
@CachePut(value="addresses", condition="#customer.name=='Tom'")
public String getAddress(Customer customer) {...}
@CachePut(value="addresses", unless="#result.length()<64")
public String getAddress(Customer customer) {...}2. 定制能力
1. Key生成
Spring提供了KeyGenerator來實現(xiàn)Key的生成,Spring 4.0之后默認采用SimpleKeyGenerator來生成Key,邏輯如下:
- 方法沒有參數(shù)的話,默認返回SimpleKey.EMPTY
- 方法就一個參數(shù),返回這個參數(shù)值
- 方法有多個參數(shù),將參數(shù)封裝為
SimpleKeySimpleKey會計算hashCode來作為緩存讀寫的Key,如果你不想要這個默認行為,可以通過SpEL自定義Key,比如
@Cacheable(cacheNames="books", key="#isbn") public Book findBook(ISBN isbn, boolean checkWarehouse, boolean includeUsed) @Cacheable(cacheNames="books", key="#isbn.rawNumber") public Book findBook(ISBN isbn, boolean checkWarehouse, boolean includeUsed) @Cacheable(cacheNames="books", key="T(someType).hash(#isbn)") public Book findBook(ISBN isbn, boolean checkWarehouse, boolean includeUsed)
除此以外,還可以自定義KeyGenerator,將自定義的KeyGenerator定義為bean后,在注解中引用
@Cacheable(cacheNames="books", keyGenerator="myKeyGenerator") public Book findBook(ISBN isbn, boolean checkWarehouse, boolean includeUsed)
SpEL中可以使用的變量如下
| Name | Description | Example |
|---|---|---|
methodName | 方法名 | #root.methodName |
method | 方法 | #root.method.name |
target | 當前方法所屬的實例 | #root.target |
targetClass | 當前方法所在的類 | #root.targetClass |
args | 方法的入?yún)?/td> | #root.args[0] |
caches | 對應的緩存 | #root.caches[0].name |
| 參數(shù)名 | 方法入?yún)⒚琂ava編譯時帶(-parameters)。否則使用#a<#idx> ,其中#idx是參數(shù)的位置(從0開始) | #iban or #a0 |
result | 方法返回值,只在unless、@CachePut的key、@CacheEvict設置beforeInvocation=false時可用。如果返回值用來包裝類(如Optional),#result引用的是內(nèi)部對象 | #result |
2. 自定義CacheManager
Spring提供了EhCache和Caffeine的默認實現(xiàn),如果使用沒有默認實現(xiàn)的Cache,可以通過自定義CacheManager來實現(xiàn)
@Bean
CacheManager cacheManager() {
CaffeineCacheManager cacheManager = new CaffeineCacheManager();
cacheManager.setCacheSpecification(...);
cacheManager.setAsyncCacheMode(true);
return cacheManager;
}3. 實現(xiàn)原理
1. Cache抽象
Spring定義了一個Cache接口,用來實現(xiàn)緩存的寫入、讀取和清理,通過CacheManager、CacheResolver創(chuàng)建Cache對象,集成Spring Boot Starter Cache的時候其實就是創(chuàng)建CacheManager。通過將KeyGenerator生成緩存key,傳遞給Cache,來設置或讀取緩存。

2. 注解實現(xiàn)
通過AOP代理了標注@Cacheable、@CacheEvict、@CachePut等注解的方法,程序的入口在ProxyCachingConfiguration中,他會創(chuàng)建Advisor和Interceptor,實現(xiàn)對Bean對象的AOP。BeanFactoryCacheOpertionSourceAdvisor內(nèi)部使用CacheOperationSource來過濾切點類,如果我們是基于Annotation來使用緩存的話,實現(xiàn)類是AnnotationCacheOperationSource,它負責失敗方法上的@Cacheable等注解。實際的緩存邏輯由CacheInterceptor實現(xiàn),核心代碼在CacheAspectSupport類內(nèi),尤其是execute方法。

CacheAspectSupport的execute方法的核心邏輯就是生成key、讀取緩存、實際調(diào)用方法、寫入緩存。

A. 參考文檔 https://docs.spring.io/spring-framework/reference/integration/cache/annotations.html
到此這篇關于Spring Cache的使用的文章就介紹到這了,更多相關Spring Cache使用內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
Springmvc DispatcherServlet原理及用法解析
這篇文章主要介紹了Springmvc DispatcherServlet原理及用法解析,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下2020-09-09
Java生成二維碼的兩種實現(xiàn)方式(基于Spring?Boot)
這篇文章主要給大家介紹了關于Java生成二維碼的兩種實現(xiàn)方式,文中的代碼基于Spring?Boot,本文基于JAVA環(huán)境,以SpringBoot框架為基礎開發(fā),文中通過實例代碼介紹的非常詳細,需要的朋友可以參考下2023-07-07
springboot中將日志信息存儲在catalina.base中過程解析
這篇文章主要介紹了springboot中將日志信息存儲在catalina.base中過程解析,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下2019-09-09
使用Maven創(chuàng)建和管理多模塊項目的詳細步驟
使用Maven進行多模塊項目管理是一種常見的做法,它可以幫助你組織大型項目,使其結(jié)構更加清晰,便于維護和構建,以下是使用Maven創(chuàng)建和管理多模塊項目的詳細步驟,需要的朋友可以參考下2024-10-10
java web開發(fā)之servlet圖形驗證碼功能的實現(xiàn)
這篇文章主要為大家詳細介紹了java web開發(fā)之servlet中圖形驗證碼,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下2017-11-11

