javascript
Spring Cache + Caffeine的整合与使用
前言
對于一些項目里需要對數據庫里的某些數據一直重復請求的,且這些數據基本是固定的,在這種情況下,可以借助簡單使用本地緩存來緩存這些數據。這些介紹一下Spring Cache和Caffeine的使用。
引入依賴和CacheConfig
在pom文件里面引入下面的依賴:
<dependency>
<groupId>com.github.ben-manes.caffeine</groupId>
<artifactId>caffeine</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cache</artifactId>
</dependency>
在啟動類上加上@EnableCaching的注解
@EnableCaching
public class SpringBootApplication{
}
新建一個CacheConfig類
@Configuration
public class CacheConfig {
/********************************
* @function : 生成緩存管理器
* @parameter : []
* @return : org.springframework.cache.CacheManager
* @date : 2023/12/13 14:46
********************************/
@Primary
@Bean("customCacheManager")
public CacheManager customCacheManager() {
SimpleCacheManager simpleCacheManager = new SimpleCacheManager();
List<Cache> cacheList = new ArrayList<>();
cacheList.add(customCache());
simpleCacheManager.setCaches(cacheList);
return simpleCacheManager;
}
/********************************
* @function : 生成自定義緩存容器
* @parameter : []
* @return : org.springframework.cache.Cache
* @date : 2023/12/13 14:46
********************************/
public Cache customCache() {
return new CaffeineCache("customCache", Caffeine.newBuilder()
.build(), true);
}
}
這里customCache()方法我并沒有設置相關過期時間和最大值,不設置會導致沒有默認過期時間和最大值。如果需要設置可以參考下面的寫法
public Cache customCache() {
return new CaffeineCache("customCache", Caffeine.newBuilder()
.maximumSize(100)
.initialCapacity(100)
.expireAfterWrite(10, TimeUnit.MINUTES)
.recordStats()
.build(),
true);
}
CaffeineCache參數的講解
- "customCache": 這是緩存的名稱。在應用程序中,你可以通過這個名稱來獲取對應的緩存實例。
-
Caffeine.newBuilder(): 這是創建Caffeine緩存實例的起始點。newBuilder()返回一個Caffeine構建器對象,用于配置和定制緩存的各種屬性。 -
.maximumSize(100): 這是設置緩存的最大容量,即緩存可以容納的最大條目數。在這個例子中,緩存的最大容量被設置為100。 -
.initialCapacity(100): 這是設置緩存的初始容量,即在緩存初始化時分配的內部數據結構的初始大小。在這個例子中,初始容量被設置為100。 -
.expireAfterWrite(10, TimeUnit.MINUTES): 這是設置緩存項在被寫入后的過期時間。在這個例子中,緩存項將在被寫入后的10分鐘內過期。 -
.recordStats(): 這是啟用緩存統計信息的選項。啟用后,你可以從緩存實例中獲取有關緩存使用情況的統計信息,例如命中率、加載次數等。
使用中,對過期策略的使用會比較重要,對于過期的策略有:
-
寫入后過期 (
expireAfterWrite): 緩存項被寫入后的一段時間內過期。可以通過以下方式配置:Caffeine.newBuilder() .expireAfterWrite(10, TimeUnit.MINUTES) .build();在上述示例中,緩存項將在被寫入后的10分鐘內過期。
-
訪問后過期 (
expireAfterAccess): 緩存項在一段時間內沒有被訪問后過期。可以通過以下方式配置:Caffeine.newBuilder() .expireAfterAccess(15, TimeUnit.MINUTES) .build();在上述示例中,緩存項將在最后一次訪問后的15分鐘內過期。
-
定時過期 (
expireAfter): 緩存項在指定的固定時間內過期,不考慮寫入或訪問。可以通過以下方式配置:Caffeine.newBuilder() .expireAfter(1, TimeUnit.HOURS) .build();在上述示例中,緩存項將在創建后的1小時內過期。
這些過期定時策略可以根據具體的使用場景和需求進行組合或選擇。
上面不同寫法將會導致生成不同的localcache實現類,可以在build方法中看到:
進入isBounded()方法:
如果使用緩存會調用localcache的get方法,最后進入computeIfAbsent()方法,對比上面兩個實現類的實現,先是BoundedLocalCache:
UnboundedLocalCache:
下面這個并不會去檢查是否過期。
使用示范
在MVC的使用,可以將緩存的注解標識于service層:
@Service
@Slf4j
@CacheConfig(cacheNames = "customCache", cacheManager = "customCacheManager")
public class CalDataInitServiceImpl implements ICalDataInitService {
@Cacheable(key = "#root.methodName + #sendCardName")
public int getSlotCount(String sendCardName) {
..方法體
return calCard.getSlotCount();
}
...
@CachePut(key = "#param")
public String updateCache(String param) {
// 對數據庫更新某個值
return updatedValue;
}
@CacheEvict(key = "#param")
public void evictCache(String param) {
// 對數據庫刪除某個值
}
}
使用到的注解解析:
@Cacheable 是Spring框架中用于聲明緩存規則的注解之一。它通常用于標記在方法上,以指示Spring在執行方法前先檢查緩存,如果緩存中已有數據,則直接返回緩存中的數據,而不執行方法體。如果緩存中沒有數據,則執行方法體,并將方法的返回值存入緩存。
以下是 以@Cacheable 注解為例的主要參數介紹和使用方式:
-
value(或cacheNames): 指定緩存的名稱,可以指定一個或多個緩存。如果指定多個緩存,Spring會依次檢查緩存,直到找到第一個有數據的緩存或全部檢查完畢。示例:@Cacheable(value = "myCache") public String getCachedData() { // 方法體 } -
key: 指定緩存項的鍵。默認情況下,Spring會使用方法的參數作為鍵,但你也可以通過key屬性指定自定義的緩存鍵。示例:@Cacheable(value = "myCache", key = "#param") public String getCachedData(String param) { // 方法體 } -
condition: 指定條件表達式,只有當條件滿足時才會緩存。示例:@Cacheable(value = "myCache", condition = "#result != null") public String getCachedData() { // 方法體 } -
unless: 指定一個條件表達式,當條件為 true 時,不會將結果放入緩存。示例:@Cacheable(value = "myCache", unless = "#result == null") public String getCachedData() { // 方法體 } -
keyGenerator: 指定自定義的緩存鍵生成器。這個屬性允許你提供一個實現了org.springframework.cache.interceptor.KeyGenerator接口的類,用于生成緩存鍵。示例:@Cacheable(value = "myCache", keyGenerator = "customKeyGenerator") public String getCachedData() { // 方法體 } -
sync: 是否啟用同步模式。如果設置為 true,可以解決并發查的問題,Spring會在調用方法時鎖定緩存,防止多個線程同時訪問數據庫。默認為 false。示例:@Cacheable(value = "myCache", sync = true) public String getCachedData() { // 方法體 }
這些是 @Cacheable 注解的一些常用參數。可以根據實際需要選擇合適的參數來定義緩存規則。
在Spring中,除了 @Cacheable,另外一些注解及其簡要介紹:
-
@CacheEvict: 用于從緩存中移除數據。通常用于在方法執行后清空指定緩存。示例:@CacheEvict(value = "myCache", key = "#param") public void evictCache(String param) { // 方法體 } -
@CachePut: 用于將方法的返回值更新到緩存中,常用于更新緩存而不影響方法的執行。示例:@CachePut(value = "myCache", key = "#param") public String updateCache(String param) { // 方法體 return updatedValue; } -
@Caching: 用于將多個緩存相關的注解組合在一起,實現復雜的緩存操作。示例:@Caching( evict = {@CacheEvict(value = "cache1", key = "#param1")}, put = {@CachePut(value = "cache2", key = "#param2")} ) public String complexCacheOperation(String param1, String param2) { // 方法體 } -
@CacheConfig: 用于在類級別配置緩存的一些公共屬性,避免在每個方法上都重復指定相同的緩存名稱等信息。示例:@CacheConfig(cacheNames = "commonCache") public class MyService { @Cacheable public String getCachedData(String param) { // 方法體 } }
這些注解可以單獨使用,也可以結合使用,以滿足不同的緩存需求。
清空緩存的方法
清空所有緩存,可以不指定 value 和 key,如下所示:
@CacheEvict(allEntries = true)
public void evictAllCaches() {
// 方法體
}
在這個例子中,allEntries = true 表示清空所有緩存。
如果你想根據某個條件來判斷是否清空緩存,可以使用 condition 屬性,例如:
@CacheEvict(value = "myCache", key = "#param", condition = "#param != 'noEviction'")
public void evictCacheConditionally(String param) {
// 方法體
}
在上述例子中,只有當 param 不等于 'noEviction' 時才會執行緩存清空操作。
除了 @CacheEvict,在一些特定場景下,@CachePut 也可以被用來“清空”緩存,因為它將方法的返回值放入緩存,如果返回值為 null,相當于移除緩存項。這種方式通常在更新操作時使用。
注意事項
如下圖代碼所示,如果在updateCache方法又調用了同個類里面的getSlotCount()方法,是不會使用到緩存的,這是因為緩存的實現是通過AOP實現,在同個類里面調用方法,實際是通過this來調,不會調用到代理對象,因此相當于@Cacheable注解在這種情況是不生效的。
@Service
@Slf4j
@CacheConfig(cacheNames = "customCache", cacheManager = "customCacheManager")
public class CalDataInitServiceImpl implements ICalDataInitService {
@Cacheable(key = "#root.methodName + #sendCardName")
public int getSlotCount(String sendCardName) {
..方法體
return calCard.getSlotCount();
}
...
@CachePut(key = "#param")
public String updateCache(String param) {
getSlotCount("xx");
// 對數據庫更新某個值
return updatedValue;
}
}
總結
以上是生活随笔為你收集整理的Spring Cache + Caffeine的整合与使用的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 聊一聊 .NET高级调试 内核模式堆泄露
- 下一篇: 懒人福音,谷歌让机器训练机器,用大语言模