Caffeine 是基於 JAVA 8 的高效能快取庫。並且在 spring5 (springboot 2.x)
後spring
官方放棄了 Guava
,而使用了效能更優秀的 Caffeine 作為預設快取元件
一、引入依賴
<dependency>
<groupId>com.github.ben-manes.caffeine</groupId>
<artifactId>caffeine</artifactId>
<version>2.8.8</version>
</dependency>
caffeine
的3.x
版本不支援jdk1.8
,所以這裡選用2.8.8
二、自定義列舉
一個專案裡可能需要快取的資料有很多,比如使用者資訊,許可權資訊,選單資訊等等,我們需要給不同的場景分配不同的名稱空間,並設定不同的過期時間
public enum CacheEnum {
/**
* 使用者快取,快取時間單位/秒
*/
CACHE_USERS("users", 2),
/**
* 選單快取,快取時間單位/秒
*/
CACHE_MENU("menu", 2),
;
/**
* 快取名稱
*/
private final String name;
/**
* 過期時間
*/
private final int expires;
}
三、快取配置類
@Slf4j
public class CacheConfig {
@Bean
public CacheManager cacheManager() {
SimpleCacheManager cacheManager = new SimpleCacheManager();
List<CaffeineCache> list = new ArrayList<>();
//迴圈新增列舉類中自定義的快取
for (CacheEnum cacheEnum : CacheEnum.values()) {
list.add(new CaffeineCache(cacheEnum.getName(),
Caffeine.newBuilder()
.initialCapacity(50)
.maximumSize(1000)
// 設定過期時間
.expireAfterWrite(cacheEnum.getExpires(), TimeUnit.SECONDS)
.build()));
}
cacheManager.setCaches(list);
log.info("[cacheManager載入完成]");
return cacheManager;
}
}
initialCapacity=[integer]:
初始的快取空間大小maximumSize=[long]:
快取的最大條數maximumWeight=[long]:
快取的最大權重expireAfterAccess=[duration]:
最後一次寫入或訪問後經過固定時間過期expireAfterWrite=[duration]:
最後一次寫入後經過固定時間過期refreshAfterWrite=[duration]:
建立快取或者最近一次更新快取後經過固定的時間間隔,重新整理快取weakKeys:
開啟key的弱引用weakValues:
開啟value的弱引用softValues:
開啟value的軟引用recordStats:
開發統計功能
注意:
expireAfterWrite
和expireAfterAccess
同事存在時,以expireAfterWrite
為準。maximumSize
和maximumWeight
不可以同時使用weakValues
和softValues
不可以同時使用
如果是在自定義的starter裡,還需要在MATE-INFO/spring.factories
中配置EnableAutoConfiguration
四、工具類
public enum CacheUtil {
/**
* 工具類標記
*/
X;
private final CacheManager cm;
CacheUtil() {
cm = SpringUtil.getBean("cacheManager", CacheManager.class);
}
/**
* 新增快取
*
* @param cacheName 快取名稱
* @param key 快取key
* @param value 快取值
*/
public void put(String cacheName, String key, Object value) {
Cache cache = cm.getCache(cacheName);
cache.put(key, value);
}
/**
* 獲取快取
*
* @param cacheName 快取名稱
* @param key 快取key
* @return
*/
public <T> Optional<T> get(String cacheName, String key) {
Cache cache = cm.getCache(cacheName);
if (cache == null) {
return Optional.empty();
}
Cache.ValueWrapper valueWrapper = cache.get(key);
if (null == valueWrapper) {
return Optional.empty();
}
return Optional.of((T) valueWrapper.get());
}
/**
* 失效快取
*
* @param cacheName 快取名稱
* @param key 快取key
*/
public void evict(String cacheName, String key) {
Cache cache = cm.getCache(cacheName);
if (cache != null) {
cache.evict(key);
}
}
}
工具類需要保證都是單例的,而列舉類天然支援單例, X
表示工具類獲取快取使用 Optional
作為返回,是為了提醒使用者可能返回null
的情況,需要做針對處理
五、單元測試
@Test
public void test_cache_put() throws InterruptedException {
CacheUtil.X.put(CacheEnum.CACHE_USERS.getName(), "users", "zhangsan");
CacheUtil.X.put(CacheEnum.CACHE_MENU.getName(), "menus", Arrays.asList("1", "2", "3", "4"));
Optional<String> users = CacheUtil.X.get(CacheEnum.CACHE_USERS.getName(), "users");
if (users.isPresent()) {
String str = users.get();
System.out.println(str);
}
Optional<List<String>> menus = CacheUtil.X.get(CacheEnum.CACHE_MENU.getName(), "menus");
menus.ifPresent(System.out::println);
// 測試快取過期情況
Thread.sleep(2000);
Optional<String> users2 = CacheUtil.X.get(CacheEnum.CACHE_USERS.getName(), "users");
if (users2.isPresent()) {
String str = users2.get();
System.out.println(str);
}
Optional<List<String>> menus2 = CacheUtil.X.get(CacheEnum.CACHE_MENU.getName(), "menus");
menus2.ifPresent(System.out::println);
}