基本概念及原理
處理邏輯
Spring Cache 是 Spring 提供的一整套的緩存解決方案。
雖然它本身并沒有提供緩存的實現,但是它提供了一整套的接口和代碼規范、配置、注解等,這樣它就可以整合各種緩存方案了
處理邏輯:每次調用某方法,而此方法又是帶有緩存功能時,Spring 框架就會檢查指定參數的那個方法是否已經被調用過,如果之前調用過,就從緩存中取之前調用的結果;如果沒有調用過,則再調用一次這個方法,并緩存結果,然后再返回結果,那下次調用這個方法時,就可以直接從緩存中獲取結果了。
實現步驟
SpringCache實現步驟 :
啟用緩存 :通過 @EnableCaching 注解觸發 Spring 的緩存代理配置
。AOP 攔截
:Spring 為標記注解的方法生成代理對象,在方法調用前后插入緩存操作。緩存處理
:根據注解配置,調用 CacheManager 獲取 Cache 實例,執行讀寫或刪除操作。
核心原理
Spring Cache 的核心原理基于 AOP(面向切面編程) 和 緩存抽象
,通過注解簡化緩存邏輯的集成。
其核心是 緩存抽象層 和 動態代理機制
,結合 Spring Boot 的自動配置,可快速集成多種緩存方案,顯著提升系統性能
Spring Cache 通過 抽象層 解耦具體緩存技術:
適配器模式
:通過 CacheManager 和 Cache 接口適配不同緩存實現(如 Redis、Ehcache)。自動配置
:Spring Boot 的 spring-boot-autoconfigure 模塊自動檢測并配置緩存實現(如引入 spring-boot-starter-data-redis 后自動啟用 Redis 緩存)。
核心組件與抽象
Cache 接口 :定義緩存操作(如 get、put、evict)
,具體實現由第三方緩存技術(如 Redis、Caffeine)提供。
CacheManager 接口 :管理多個 Cache 實例,負責創建、配置和獲取緩存對象
。
例如:
- ConcurrentMapCacheManager(默認內存緩存)
- RedisCacheManager(Redis 實現)
- EhCacheCacheManager(Ehcache 實現)
核心注解
Spring 提供了五個注解來聲明緩存規則。
@Cacheable:方法執行前檢查緩存,命中則直接返回,否則執行方法并緩存結果
。@CachePut:方法調用前不會去緩存中查找,無論緩存是否存在,都執行方法并更新緩存
。@CacheEvict:刪除指定緩存
,清除緩存中的一條或多條記錄@Caching:組合多個緩存操作
。@CacheConfig:在類級別共享相同的緩存的配置
注解 | 作用 | 常用參數 |
---|---|---|
@Cacheable | 方法結果緩存(先查緩存,未命中執行方法),一般用在查詢方法上 | value, key, condition |
@CachePut | 強制更新緩存(始終執行方法),一般用在新增方法上 | value, key, unless |
@CacheEvict | 清除緩存,一般用在更新或者刪除方法上 | value, key, allEntries |
@Caching | 組合多個緩存操作,實現同一個方法上同時使用多種注解 | cacheable, put, evict |
@CacheConfig | 類級別共享緩存配置 | cacheNames, keyGenerator |
SpEL 表達式
場景 | 表達式示例 |
---|---|
防緩存穿透 | unless = “#result == null” |
多字段復合鍵 | key = “#user.id + ‘:’ + #user.deviceId” |
時間戳動態鍵 | key = “T(System).currentTimeMillis()” |
權限過濾 | condition = “#authLevel > 3” |
集合非空判斷 | condition = “!#list.isEmpty()” |
還有許多其他的表達式,待使用時再去專門查詢吧
實現
pom依賴
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-cache</artifactId>
</dependency>
選擇使用的緩存
# 使用redis進行緩存
spring.cache.type=redis
Spring Cache 支持很多緩存中間件作為框架中的緩存,總共有 9 種選擇:
- caffeine:Caffeine 是一種高性能的緩存庫,基于 Google Guava。
- couchbase:CouchBase是一款非關系型JSON文檔數據庫。
- generic:由泛型機制和 static 組合實現的泛型緩存機制。
- hazelcast:一個高度可擴展的數據分發和集群平臺,可用于實現分布式數據存儲、數據緩存。
- infinispan:分布式的集群緩存系統。
- jcache:JCache 作為緩存。它是 JSR107 規范中提到的緩存規范。
- none:沒有緩存。
- redis:用 Redis 作為緩存
- simple:用內存作為緩存
測試緩存
基本概念
在啟動類上面添加@EnableCaching注解
指定某方法開啟緩存功能。在方法上添加 @Cacheable 緩存注解就可以了。
@Cacheable 注解中,可以添加四種參數:value,key,condition,unless
- value:指定緩存名稱(必填)
- key:自定義緩存鍵(SpEL表達式)
- condition:執行前條件判斷(SpEL)
- unless:執行后結果過濾(SpEL)
參數 | 類型 | 作用 | 示例 |
---|---|---|---|
value | String[] | 指定緩存名稱(必填) | value = “users” 或 value = {“cache1”, “cache2”} |
key | String | 自定義緩存鍵(SpEL表達式) | key = "#userId"或key = “T(java.util.UUID).randomUUID().toString()” |
condition | String | 執行前條件判斷(SpEL) | condition = "#userId > 1000"或condition = “#name.startsWith(‘admin’)” |
unless | String | 執行后結果過濾(SpEL) | unless = "#result == null"或unless = “#result.age < 18” |
使用示例1
第一次調用下面這個接口前,緩存里面是沒有hot緩存,也沒有這個test方法的結果緩存
調用test方法后,緩存中便會創建出hot這個緩存,其中緩存了一個key(默認值SimpleKey[]),其中有一個值
- 緩存中 key 對應的 value 默認使用 JDK 序列化后的數據。
- value 的過期時間為 -1,表示永不過期。
key:hot:SimpleKey[]
value:222
@RequestMapping("/test2")
@Cacheable({"hot"})
public int test() {return 222;
}
第二次調用test()方法時,便會直接讀緩存,而不去執行test里面的方法
@RequestMapping("/test2")
@Cacheable({"hot"})
public int test2() {return 456;
}
如果再將類名改為test2后,緩存獲取到的值還是test方法時緩存的值222,因為兩個方法的key值都是SimpleKey[]
使用示例2
// 啟用緩存(配置類)
@EnableCaching
@Configuration
public class CacheConfig {@Beanpublic CacheManager cacheManager() {return new ConcurrentMapCacheManager("users"); // 內存緩存}
}// 業務層使用
@Service
public class UserService {// 緩存讀取(value=緩存名稱,key=緩存鍵)@Cacheable(value = "users", key = "#userId")public User getUserById(Long userId) {// 實際數據庫查詢return userRepository.findById(userId);}// 緩存更新@CachePut(value = "users", key = "#user.id")public User updateUser(User user) {return userRepository.save(user);}// 緩存清除@CacheEvict(value = "users", key = "#userId")public void deleteUser(Long userId) {userRepository.deleteById(userId);}
}
自定義配置類
自定義緩存過去時間等
# 使用 Redis 作為緩存組件
spring.cache.type=redis
# 緩存過期時間為 3600s
spring.cache.redis.time-to-live=3600000
# 緩存的鍵的名字前綴
spring.cache.redis.key-prefix=passjava_
# 是否使用緩存前綴
spring.cache.redis.use-key-prefix=true
# 是否緩存控制,防止緩存穿透
spring.cache.redis.cache-null-values=true
自定義 key
在 @Cacheable 注解里面加上 key 的值 #root.method.name。這是一種特有的表達式,稱作 SpEL 表達式,這里代表用方法名作為緩存 key 的名字
@Cacheable(value = {"hot"}, key = "#root.method.name")
如果按上述去配置的話,緩存的key的名稱便是這個方法名
自定義條件
可以自定義條件來決定是否將緩存功能關閉。這里就要用到@Cacheable 另外兩個屬性:condition 和 unless,它倆的格式還是用 SpEL 表達式