Spring緩存抽象
Spring從3.1開始定義了一系列抽象接口來統一不同的緩存技術;並支持使用JCache(JSR-107)註解簡化我們進行緩存開發。Spring Cache 只負責維護抽象層,具體的實現由你的技術選型來決定。將緩存處理和緩存技術解除耦合。
依賴引入
Spring cache 抽象由spring-context相關組件實現。非Spring Boot 項目可通過引入該模塊進行集成。
Spring Boot 項目可引入以下依賴:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cache</artifactId>
</dependency>
同時可能需要引入你採用的緩存中間件客戶端;比如 Ehcache、redis等。
兩個重要抽象概念
- Cache 緩存抽象規範接口,定義緩存一些了操作。實現有:RedisCache、EhCacheCache、ConcurrentMapCache等
- CacheManager 緩存管理器,管理Cache的生命週期。
常用的一些註解
Spring cache 提供了一系列的註解,將我們從編程開發中解放出來。讓我們更加關注於業務開發。
@EnableCaching
該註解是啓用Spring cache 的開關。必須開啓才能使用Spring cache相關功能。
@Cacheable
可以標記在一個方法或者類上。方法級只針對該方法。類上則針對類內所有的方法。對於一個支持緩存的方法,Spring會在其被調用後將其返回值緩存起來,以保證下次利用同樣的參數來執行該方法時可以直接從緩存中獲取結果,而不需要再次執行該方法。Spring在緩存方法的返回值時是以鍵值對進行緩存的,值就是方法的返回結果。
public @interface Cacheable {
@AliasFor("cacheNames")
String[] value() default {};
//和value註解差不多,二選一
String[] cacheNames() default {};
// 該次緩存的key
String key() default "";
//key的生成器。key/keyGenerator二選一使用
String keyGenerator() default "";
//指定緩存管理器 一般使用默認
String cacheManager() default "";
//或者指定獲取解析器 一般使用默認
String cacheResolver() default "";
//條件符合則緩存 使用的比較多 支持SpEL
String condition() default "";
//條件符合則不緩存 使用的比較多 支持SpEL
String unless() default "";
//是否使用異步模式
boolean sync() default false;
}
後面有個別註解屬性跟這個基本相同不進行重複介紹。
@CacheConfig
作用於緩存接口上,來對該接口下的一些重複配置(緩存名稱、key生成器、緩存管理器、緩存處理器)進行歸納處理。其他屬性可參考Cacheable。
@CachePut
該註解容易跟@Cacheable混淆。兩者都可以執行緩存的“放入”操作,不同於@Cacheable,@CachePut每次都將執行方法並將返回值K-V放入緩存,如果該K存在則進行更新。其他屬性可參考Cacheable。
@CacheEvict
@CachEvict主要針對方法配置,能夠根據一定的條件對特定的緩存進行清空。該註解有兩個特別的屬性:
- allEntries 是否清空所有緩存內容,缺省爲 false,如果指定爲 true,則方法調用後將立即清空所有緩存。注意不能跟key參數同時使用。
- beforeInvocation 是否在方法執行前就清空,缺省爲 false,如果指定爲 true,則在方法還沒有執行的時候就清空緩存,缺省情況下,如果方法執行拋出異常,則不會清空緩存。
@Caching
該註解是個組合註解。有時候我們需要在一個方法上同時使用多個相同註解但是java是不支持一個註解在同一個方法上多次使用。這時就可以使用該註解進行組合。
使用要點
- 緩存註解所在的方法不能在類中進行內部調用。
- 緩存一定要有過期超時策略,避免系統不堪重負。
- 緩存的值如果是集合考慮對集合的大小的限制,避免序列化/反序列化性能。
緩存實戰
接下來我們通過Spring cache 集合redis 來實戰一下,甚至有一些特別的玩法。假設redis環境已經搭建好了。Spring Boot 項目中引入:
<!-- redis -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!-- spring cache -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cache</artifactId>
</dependency>
<!-- lettuce 必備依賴 -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
</dependency>
在yml配置中我們大多可使用默認配置。配置spring.cache.type=REDIS
。其他配置可通過前綴
spring.cache
、spring.redis
進行配置。
使用非阻塞反應式redis客戶端
Spring Boot 2.x中 默認使用lettuce作爲默認redis客戶端。當然你也可以引入redisson客戶端。建議放棄阻塞客戶端jedis。
對緩存進行自定義配置
如果我們使用默認的配置那麼所有的K-V都不會自動過期。很多情況下我們有這樣的需求,驗證碼緩存5分鐘自動過期,區域信息30分鐘。那麼我們就需要自定義 CacheManager。代碼如下:
public CacheManager cacheManager(RedisConnectionFactory redisConnectionFactory) {
return RedisCacheManager.RedisCacheManagerBuilder.fromCacheWriter(RedisCacheWriter.nonLockingRedisCacheWriter(redisConnectionFactory))
// 默認策略,未配置的 key 會使用這個
.cacheDefaults(redisConfig(60))
// 自定義 key 策略
.withInitialCacheConfigurations(redisCacheConfigurationMap()).build();
}
cacheDefaults方法用來指定默認配置,withInitialCacheConfigurations方法用來對各種緩存空間進行個性化配置。redisCacheConfigurationMap方法是一個以緩存名稱爲key,其對應的redis配置類爲值得鍵值映射。這個需要在開發中自己進行配置。參考CacheNameEnum
。
編寫緩存處理類
經過上面的配置後,我們編寫以下緩存類:
/**
* The type Captcha cache.
*
* @author dax
* @since 2019 /9/2 21:31
* @see cn.felord.rediscache.config.CacheNameEnum
*/
@Slf4j
@Component
@CacheConfig(cacheNames = {"smsCode"})
public class CaptchaCache {
@CachePut(key = "#key")
public String put(String key,String code){
log.info("執行 cachePut");
return code;
}
@CacheEvict(key = "#key")
public void expire(String key){
}
@Cacheable(key = "#key")
public String get(String key){
return null;
}
}
請注意 緩存名稱 smsCode
在CacheNameEnum
進行了個性化配置。
總結
到上面我們的spring cache 緩存就搞完了。樣例已經上傳到了我的碼雲倉庫,你可以通過以下地址:
https://gitee.com/felord/redi...
獲取demo,結合本文進行學習一些高級玩法來應對你的業務開發。
關注公衆號:碼農小胖哥 獲取更多資訊