Springboot集成一二级缓存(caffeine+redis)
·
目的:主要是实现查询效率上的优化,减少数据库方面的压力,提升系统的性能
L1:一级缓存,主要是本地内存缓存,不需要网络传输,实时性很高,适合存储数据量少的数据,不可以持久化存储。
L2:二级缓存,独立于服务器/程序之外的外部缓存,适合存储数据量大大一点的数据,可持久化存储,性能稍慢于一级缓存,如redis,支持集群部署,多节点共享数据。
1.maven依赖
对于2.7.x及以上版本的无需指定caffeine版本号,spring会自动去引入兼容版本。 <dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cache</artifactId>
</dependency>
<dependency>
<groupId>com.github.ben-manes.caffeine</groupId>
<artifactId>caffeine</artifactId>
</dependency>
2.开始配置
2.1 添加@EnableCaching注解
在启动类上添加@EnableCaching开关。@EnableCaching
@SpringBootApplication
public class SystemApplication {
.......
}
2.2 创建CacheConfig类,注入到spring管理中
一个是Caffeine本地缓存管理器,一个是多级缓存管理器。@Configuration
@EnableCaching
public class CacheConfig {
@Bean
public CacheManager caffeineCacheManager() {
CaffeineCacheManager cacheManager = new CaffeineCacheManager();
cacheManager.setCaffeine(Caffeine.newBuilder()
// 初始化容量
.initialCapacity(100)
// 最大容量
.maximumSize(1000)
// 过期时间
.expireAfterWrite(3600, TimeUnit.SECONDS)
.recordStats());
return cacheManager;
}
* 一二级缓存管理器
*
* @param caffeineCacheManager Caffeine缓存管理
* @param redisCacheUtil redis工具类
* @return
*/
@Primary
@Bean
public CacheManager levelCacheManager(@Qualifier(value = "caffeineCacheManager") CacheManager caffeineCacheManager,
@Autowired RedisCacheUtil redisCacheUtil) {
return new LevelCacheManager(caffeineCacheManager, redisCacheUtil);
}
}
2.3 创建一二级缓存管理器
里面同时实现了对每个key值自定义过期时间,默认是设置通用过期时长。public class LevelCacheManager implements CacheManager {
private final CaffeineCacheManager caffeineCacheManager;
private final RedisCacheUtil redisCacheUtil;
public LevelCacheManager(CacheManager caffeineCacheManager, RedisCacheUtil redisCacheUtil) {
this.caffeineCacheManager = (CaffeineCacheManager) caffeineCacheManager;
this.redisCacheUtil = redisCacheUtil;
}
@Override
public Cache getCache(String name) {
CaffeineCache caffeineCache = parseName(name);
return new LevelCache(name, caffeineCache, redisCacheUtil);
}
@Override
public Collection<String> getCacheNames() {
return Collections.emptyList();
}
private CaffeineCache parseName(String name) {
long duration = 0; // 默认60分钟
if (name.contains("#")) {
// 解析名称中的有效期信息
String[] parts = name.split("#");
name = parts[0];
if (parts.length > 1) {
try {
duration = Long.parseLong(parts[1]);
} catch (NumberFormatException e) {
e.printStackTrace();
}
}
}
com.github.benmanes.caffeine.cache.Cache<Object, Object> build = Caffeine.newBuilder()
// 初始化容量
.initialCapacity(100)
// 最大容量
.maximumSize(1000)
// 过期时间
.expireAfterWrite(duration, TimeUnit.SECONDS).recordStats().build();
CaffeineCache caffeineCache = (CaffeineCache) caffeineCacheManager.getCache(name);
CaffeineCache caffeineCache2 = new CaffeineCache(name, build);
if (duration > 0) {
redisCacheUtil.setEXPIRE_TIME(duration);
return caffeineCache2;
}
redisCacheUtil.setEXPIRE_TIME(3600L);
return caffeineCache;
}
2.4 自定义一,二级缓存操作类
实现一二级缓存顺序读取,先查一级再查二级缓存,序列化方式保持一致。public class LevelCache implements Cache {
private final RedisCacheUtil redisCacheUtil;
private final String name;
private final CaffeineCache caffeineCache;
public LevelCache(String name, CaffeineCache caffeineCache, RedisCacheUtil redisCacheUtil){
this.name=name;
this.caffeineCache = caffeineCache;
this.redisCacheUtil = redisCacheUtil;
}
@Override
public String getName() {
return name;
}
/**
* 仅当缓存中不存在指定键时,才将键值对存入缓存。若键已存在,不会进行覆盖操作,而是返回缓存中现有的值。
* @param key
* @param value
* @return
*/
@Override
public ValueWrapper putIfAbsent(Object key, Object value) {
ValueWrapper existingValue = this.get(key);
if (existingValue == null) {
caffeineCache.put(key, value);
}
Object obj = redisCacheUtil.get(String.valueOf(key));
if (obj==null){
redisCacheUtil.set(String.valueOf(key),value,redisCacheUtil.getEXPIRE_TIME());
}
return this.get(key);
}
@Override
public Object getNativeCache() {
return null;
}
/**
* 获取缓存中的数据
* @param key
* @return
*/
@Override
public ValueWrapper get(Object key) {
ValueWrapper valueWrapper = caffeineCache.get(key);
if (valueWrapper != null){
return valueWrapper;
}
Object value= redisCacheUtil.get(String.valueOf(key));
if(value!=null){
caffeineCache.put(key, value);
return this.get(key);
}
return null;
}
/**
* 获取缓存中数据,具体对象
* @param key
* @param type
* @return
* @param <T>
*/
@Override
public <T> T get(Object key, Class<T> type) {
T value = caffeineCache.get(key, type);
if (value != null){
return value;
}
Object rValue = redisCacheUtil.get(String.valueOf(key));
if (rValue != null){
caffeineCache.put(key,rValue);
return (T) rValue;
}
return null;
}
/**
* 如果一二级缓存中都不存在情况下,使用自定义的valueLoader加载数据,并缓存到一级缓存和二级缓存中
* @param key
* @param valueLoader
* @return
* @param <T>
*/
@Override
public <T> T get(Object key, Callable<T> valueLoader) {
ValueWrapper value=this.get(key);
if (value!=null) {
return (T) value.get();
}else{
Object obj;
try {
obj = valueLoader.call();
} catch (Exception e) {
throw new RuntimeException(e);
}
caffeineCache.put(key,obj);
redisCacheUtil.set(String.valueOf(key),obj,redisCacheUtil.getEXPIRE_TIME());
return (T)obj;
}
}
/**
* 填入一二级缓存
* @param key
* @param value
*/
@Override
public void put(Object key, Object value) {
caffeineCache.put(key,value);
redisCacheUtil.set(String.valueOf(key),value,redisCacheUtil.getEXPIRE_TIME());
}
/**
* 移除指定key值的一二级缓存
* @param key
*/
@Override
public void evict(Object key) {
caffeineCache.evict(key);
redisCacheUtil.del(String.valueOf(key));
}
/**
* 删除所有一二级缓存
*/
@Override
public void clear() {
caffeineCache.clear();
redisCacheUtil.delByPrefix(CacheKeyGenerator.KEY_PREFIX);
}
}
2.5 自定义key值前缀工具类
在配合方法参数时,可以自己拼接前缀在key前面,实现统一管理。public class CacheKeyGenerator {
public static final String KEY_PREFIX = "levelCache:";
public static final String USER_CACHE = "userCaches";
public static String generateKey(String name) {
return KEY_PREFIX + name;
}
}
2.6 使用注解方式实现案例
@Cacheable(cacheNames = CacheKeyGenerator.USER_CACHE+"#10",
key= "T(com.makingTeam.config.cache.CacheKeyGenerator).generateKey(#name)")
public Object login(String name, String pwd) {
Map<Object, Object> objectObjectMap = new HashMap<>();
objectObjectMap.put(name, pwd);
log.info("login-----查找数据库");
return objectObjectMap;
}
@CachePut(cacheNames = CacheKeyGenerator.USER_CACHE+"#30",
key= "T(com.makingTeam.config.cache.CacheKeyGenerator).generateKey(#name)")
public Object updateLogin(String name, String pwd) {
Map<Object, Object> objectObjectMap = new HashMap<>();
objectObjectMap.put(name, pwd);
log.info("updateLogin----查找数据库");
return objectObjectMap;
}
@CacheEvict(cacheNames = CacheKeyGenerator.USER_CACHE,
key= "T(com.makingTeam.config.cache.CacheKeyGenerator).generateKey(#name)")
public void del(String name) {
log.info("del----删除");
}
完结!!!
更多推荐




所有评论(0)