springcache支持使用Caffine 和redis等等作为扩展使用。
使用Caffine,这个适合单机,但是不是很好控制。
所以使用redis。
第一个,新建 RedisCacheConfig 类
package com.lzy.myapp.config;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.CachingConfigurerSupport;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.cache.interceptor.KeyGenerator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.data.redis.cache.RedisCacheConfiguration;
import org.springframework.data.redis.cache.RedisCacheWriter;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.serializer.RedisSerializationContext;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.util.CollectionUtils;
import java.time.Duration;
/***
* caffeine 配置
* @author ZiYao Lee
* @date 2022/11/23
*/
@Configuration
@EnableCaching
@Slf4j
public class RedisCacheConfig extends CachingConfigurerSupport {
@Bean
@Primary
@Override //继承上面这个类,并且加上这个之后才能把它设置为默认的。
public KeyGenerator keyGenerator() {
return (target, method, params) -> {
String re= String.format("%s::%s(%s)",target.getClass().getName(),method.getName(),
CollectionUtils.arrayToList(params));//Arrays.asList(params)
log.debug("缓存生成的key:{}。",re);
return re;
};
}
@Bean
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
redisTemplate.setConnectionFactory(factory);
// 指定key的序列化方式:string
redisTemplate.setKeySerializer(RedisSerializer.string());
// 指定value的序列化方式:json
redisTemplate.setValueSerializer(RedisSerializer.json());
redisTemplate.setHashKeySerializer(RedisSerializer.string());
redisTemplate.setHashValueSerializer(RedisSerializer.json());
return redisTemplate;
}
@Primary
@Bean(name = "cacheManager")
public CacheManager cacheManager(RedisConnectionFactory factory) {
RedisCacheConfiguration cacheConfiguration =
RedisCacheConfiguration.defaultCacheConfig()
.disableCachingNullValues()
.entryTtl(Duration.ofMinutes(5))
.serializeValuesWith(
RedisSerializationContext.SerializationPair.fromSerializer(
RedisSerializer.json()));
return new MyRedisCacheManager(RedisCacheWriter.nonLockingRedisCacheWriter(factory), cacheConfiguration);
}
@Bean(name = "specCacheManager")
public CacheManager specCacheManager(RedisConnectionFactory factory) {
RedisCacheConfiguration cacheConfiguration =
RedisCacheConfiguration.defaultCacheConfig()
.disableCachingNullValues()
.entryTtl(Duration.ofMinutes(60))
.serializeValuesWith(
RedisSerializationContext.SerializationPair.fromSerializer(
RedisSerializer.json()));
return new MyRedisCacheManager(RedisCacheWriter.nonLockingRedisCacheWriter(factory), cacheConfiguration);
}
二,就是创建 MyRedisCacheManager
import org.apache.commons.lang3.StringUtils;
import org.springframework.data.redis.cache.RedisCache;
import org.springframework.data.redis.cache.RedisCacheConfiguration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.cache.RedisCacheWriter;
import java.time.Duration;
/**
* xx模块 - MyRedisCacheManager
*
* @author 李子耀
* @version 1.0.0
* @className MyRedisCacheManager
* @description MyRedisCacheManager
* @date 2023-9-25 10:58
*/
public class MyRedisCacheManager extends RedisCacheManager {
public MyRedisCacheManager(RedisCacheWriter writer, RedisCacheConfiguration defaultCacheConfiguration) {
super(writer,defaultCacheConfiguration);
}
@Override
protected RedisCache createRedisCache(String name, RedisCacheConfiguration cacheConfig) {
if(!StringUtils.isEmpty(name) && name.contains("#")) {
String numStr = name.split("#")[1];
if(StringUtils.isNumeric(numStr)) {
return super.createRedisCache(name, cacheConfig.entryTtl(Duration.ofSeconds(Integer.parseInt(numStr))));
}
}
return super.createRedisCache(name, cacheConfig);
}
}
处理缓存,直接在value集合后面,拼上#加上你的秒数。这样动态生成缓存。
然后就是@Cacheable的使用。
1、可以放在实现类上。
第一种方式key = "'user_id_'+#id",unless = "#result == null")
@Cacheable(value = "user",key = "'user_id_'+#id",unless = "#result == null")
public User selectByPrimaryKey(Integer id) {
return userMapper.selectByPrimaryKey(id);
}
可以读到参数值Integer id
第二种方式key = "'user_id_'+#p0",unless = "#result == null")
@Cacheable(value = "user",key = "'user_id_'+#p0",unless = "#result == null")
public User selectByPrimaryKey(Integer id) {
return userMapper.selectByPrimaryKey(id);
}
也可以读到参数值Integer id
2、可以放在接口上。
第一种方式可以读到Integer id值
@Cacheable(value = "user",key = "'user_id_'+#p0",unless = "#result == null")
User selectByPrimaryKey(Integer id);
第二种方式读不到Integer id值,值是null,
@Cacheable(value = "user",key = "'user_id_'+#id",unless = "#result == null")
User selectByPrimaryKey(Integer id);
差别就是,放在接口上,只能用p0这个去获取,而不能显式使用字符去获取。
cacheNames 对应上面的@Bean(name = "cacheManager")和@Bean(name = "specCacheManager")。 但是我使用了这个优化MyRedisCacheManager,所以可以默认使用cacheManager。
其他就很方便了。