最强本地缓存Caffeine
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);
}