最強本地快取Caffeine

孙半仙人發表於2024-03-09

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>
  • caffeine3.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:開發統計功能

注意:

  • expireAfterWriteexpireAfterAccess同事存在時,以expireAfterWrite為準。
  • maximumSizemaximumWeight不可以同時使用
  • weakValuessoftValues不可以同時使用

如果是在自定義的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);
}

相關文章