Caffeine 是基于 JAVA 8 的高性能缓存库。并且在 spring5 (springboot 2.x) 后spring 官方放弃了 Guava,而使用了性能更优秀的 Caffeine 作为默认缓存组件。其配置也相当简单,本文主要实现可以自定义多个缓存,并且针对不同缓存可以设置不同过期时间。
# gradle
implementation "com.github.ben-manes.caffeine:caffeine"
# maven
<dependency>
<groupId>com.github.ben-manes.caffeine</groupId>
<artifactId>caffeine</artifactId>
</dependency>
这里我把公共的常量提取一层,复用
public class CacheConstants {
/**
* 默认过期时间(配置类中我使用的时间单位是秒,所以这里如 3*60 为3分钟)
*/
public static final int DEFAULT_EXPIRES = 3 * 60;
public static final int EXPIRES_5_MIN = 5 * 60;
public static final int EXPIRES_10_MIN = 10 * 60;
public static final String GET_MENU = "GET:MENU:";
public static final String GET_MENU_LIST = "GET:MENU:LIST:";
}
自定义缓存名称并添加到枚举中
public enum CacheEnum {
/**
* 获取菜单
*/
GET_MENU(CacheConstants.GET_MENU, CacheConstants.EXPIRES_5_MIN),
/**
* 获取菜单列表
*/
GET_MENU_LIST(CacheConstants.GET_MENU_LIST, CacheConstants.EXPIRES_10_MIN),
;
/**
* 缓存名称
*/
private final String name;
/**
* 过期时间
*/
private final int expires;
/**
* 构造
*/
CacheEnum(String name, int expires) {
this.name = name;
this.expires = expires;
}
public String getName() {
return name;
}
public int getExpires() {
return expires;
}
}
import com.github.benmanes.caffeine.cache.Caffeine;
import org.springframework.cache.CacheManager;
import org.springframework.cache.caffeine.CaffeineCache;
import org.springframework.cache.support.SimpleCacheManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;
@Configuration
public class CacheConfig {
/**
* Caffeine配置说明:
* 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不可以同时使用
*/
@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);
return cacheManager;
}
}
在项目中和其它本地缓存一样使用方式,用spring自带的缓存注解,简洁易懂。
/**
* Cacheable
* value:缓存key的前缀。
* key:缓存key的后缀。
* sync:设置如果缓存过期是不是只放一个请求去请求数据库,其他请求阻塞,默认是false(根据个人需求)。
* unless:不缓存空值,这里不使用,会报错
*/
@Cacheable(value = CacheConstants.GET_MENU, key = "#code", sync = true)
public MenuVO getMenu(String code) {
//业务代码
}
@Cacheable(value = CacheConstants.GET_MENU_LIST, key = "#page+':'+#pageSize", sync = true)
public PaginationResult<MenuVO> getMenuList(Integer page, Integer pageSize) {
//业务代码
}
缓存失效也是一样的,可以同时失效多个,也可以失效一个,这里举例多个。一样使用自带的注解,其它操作就不一一列举了。
@Caching(evict = {
@CacheEvict(value = CacheConstants.GET_MENU_LIST, allEntries = true),
@CacheEvict(value = CacheConstants.GET_MENU, key = "#code")
})
public Boolean delete(String code) {
//删除业务代码
}
如果你不想使用 spring 自带注解,你也可以自己加个工具类操作缓存,如下:
import java.util.Objects;
import javax.annotation.PostConstruct;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.Cache;
import org.springframework.cache.CacheManager;
import org.springframework.stereotype.Component;
@Component
public class CacheUtil {
@Autowired
private CacheManager cacheManager;
private static CacheManager cm;
@PostConstruct
public void init() {
cm = cacheManager;
}
/**
* 添加缓存
*
* @param cacheName 缓存名称
* @param key 缓存key
* @param value 缓存值
*/
public static void put(String cacheName, String key, Object value) {
Cache cache = cm.getCache(cacheName);
cache.put(key, value);
}
/**
* 获取缓存
*
* @param cacheName 缓存名称
* @param key 缓存key
* @return
*/
public static Object get(String cacheName, String key) {
Cache cache = cm.getCache(cacheName);
if (cache == null) {
return null;
}
return Objects.requireNonNull(cache.get(key)).get();
}
/**
* 获取缓存(字符串)
*
* @param cacheName 缓存名称
* @param key 缓存key
* @return
*/
public static String getString(String cacheName, String key) {
Cache cache = cm.getCache(cacheName);
if (cache == null) {
return null;
}
Cache.ValueWrapper wrapper = cache.get(key);
if (wrapper == null) {
return null;
}
return Objects.requireNonNull(wrapper.get()).toString();
}
/**
* 获取缓存(泛型)
*
* @param cacheName 缓存名称
* @param key 缓存key
* @param clazz 缓存类
* @param <T> 返回值泛型
* @return
*/
public static <T> T get(String cacheName, String key, Class<T> clazz) {
Cache cache = cm.getCache(cacheName);
if (cache == null) {
return null;
}
Cache.ValueWrapper wrapper = cache.get(key);
if (wrapper == null) {
return null;
}
return (T) wrapper.get();
}
/**
* 失效缓存
*
* @param cacheName 缓存名称
* @param key 缓存key
*/
public static void evict(String cacheName, String key) {
Cache cache = cm.getCache(cacheName);
if (cache != null) {
cache.evict(key);
}
}
}
工具类项目中使用:
@Service
public class AService {
public void AMethod(){
//添加缓存
CacheUtil.put(CacheConstants.GET_MENU, "MANAGE_MENU", "........");
//获取缓存
String cacheStartTime = CacheUtil.get(CacheConstants.GET_MENU, "MANAGE_MENU", String.class);
//失效缓存
CacheUtil.evict(CacheConstants.GET_MENU, "MANAGE_MENU");
}
}