spring boot 基于注解式的缓存的配置redis
首先说说自己使用的Spring的版本是5.1.6.RELEASE,不同版本的配置会有所不一样
在网上找了一堆资料,关于redis的配置,基本上都是如下这种样子,我们首先来看看
代码如下
@Configuration
@EnableCaching
public class RedisConfig extends CachingConfigurerSupport {
@Bean
public CacheManager cacheManager(@SuppressWarnings("rawtypes") RedisTemplate redisTemplate) {
RedisCacheManager rm = new RedisCacheManager(redisTemplate);
rm.setDefaultExpiration(30l);// 设置缓存时间
return rm;
}
@Bean
@Override
public Object generate(Object target, Method method, Object... params) {
StringBuilder sb = new StringBuilder();
sb.append(target.getClass().getName());
sb.append(method.getName());
for (Object obj : params) {
sb.append(obj.toString());
}
return sb.toString();
}
@Bean
public RedisTemplate<String, String> redisTemplate(RedisConnectionFactory factory) {
StringRedisTemplate template = new StringRedisTemplate(factory);
@SuppressWarnings({ "rawtypes", "unchecked" })
Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
ObjectMapper om = new ObjectMapper();
om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
jackson2JsonRedisSerializer.setObjectMapper(om);
template.setValueSerializer(jackson2JsonRedisSerializer);
template.afterPropertiesSet();
return template;
}
}
但是这种方式在5.1.6中并不适用,
有如下几个问题:
- RedisCacheManager 并不能通过RedisTemplate来实例,
也就是说RedisCacheManager rm = new RedisCacheManager(redisTemplate);
这一段代码是会报错的
没办法了,只有靠自己,一步步看源码来操作了
首先查看RedisCacheManager 的创建方式主要有三种,分别是通过RedisConnectionFactory,RedisCacheWriter,RedisCacheConfiguration或者这三者之间的组合方式来创建的,
并且有一些创建方式还是私有的,有兴趣的可以自己看源码了
我这里用了一个比较简单的方式 RedisConnectionFactory 来创建 RedisCacheManager,
@Bean
public CacheManager cacheManager(RedisConnectionFactory factory) {
return RedisCacheManager.create(factory);
}
如果这样操作了,那就会引发第二个问题,我们序列化到redis中的数据,并不是json格式。
2. value 序列化方式
查看其它几种创建方式有没有能指定序列化方式的参数发现在RedisCacheConfiguration中有这样两个实例变量
private final SerializationPair<String> keySerializationPair;
private final SerializationPair<Object> valueSerializationPair;
很明显需要将序列化方式设置到RedisCacheConfiguration
中并通过RedisCacheConfiguration
这种方式来创建RedisCacheManager
最后将我自己的配置代码贴出来,供参考,需要注意的是,一下的代码会将部分的空数据也缓存起来,如果不需要可以在RedisCacheConfiguration
中设为为不缓存空数据
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
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.data.redis.cache.RedisCacheConfiguration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.*;
import java.time.Duration;
/**
* @author John·Louis
* <p>
* Date: 2019/7.24
* Description:
*
*/
@Configuration
@EnableCaching
public class RedisConfiguration extends CachingConfigurerSupport {
private static final String KEY_SEPARATE = "_";
private static final int DURATION_TIME = 1 * 6;
/**
*这种方式是在手动指定RedisTemplate的时候会将value序列化为json格式存储到redis数据库,
* 基于Spring Cacheable注解这种方式,序列化为json需要按照cacheManager中指定的方式
*
*/
@Bean("redisTemplate")
public <String,T> RedisTemplate<String,T> redisTemplate(RedisConnectionFactory factory) {
RedisTemplate<String, T> template = new RedisTemplate<>();
template.setConnectionFactory(factory);
Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<>(Object.class);
ObjectMapper om = new ObjectMapper();
om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
jackson2JsonRedisSerializer.setObjectMapper(om);
template.setValueSerializer(jackson2JsonRedisSerializer);
template.setKeySerializer(stringRedisSerializer());
template.afterPropertiesSet();
return template;
}
@Bean
public StringRedisSerializer stringRedisSerializer() {
return new StringRedisSerializer();
}
@Bean
public CacheManager cacheManager(RedisConnectionFactory factory) {
RedisCacheConfiguration cacheConfiguration = RedisCacheConfiguration
.defaultCacheConfig()
// 指定过期时间
.entryTtl(Duration.ofHours(DURATION_TIME))
// 指定值value序列方式
.serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(RedisSerializer.json()));
return RedisCacheManager.builder(factory)
.cacheDefaults(cacheConfiguration)
.build();
}
@Bean
public KeyGenerator keyGenerator() {
return (target, method, params) -> {
StringBuilder sb = new StringBuilder();
sb.append(target.getClass().getSimpleName()).append(KEY_SEPARATE)
.append(method.getName());
for (Object param : params) {
sb.append(KEY_SEPARATE).append(param);
}
return sb.toString();
};
}
}
最后启动程序,在service上添加注解@Cacheable(cacheNames = "comment_cache",keyGenerator = "keyGenerator")
查询程序,
然后通过redis Desktop manager 来查看存储数据如下,
完美
{
"@class": "com.louis.comment.entity.OrderComment",
"id": 2,
"orderId": 3,
"commentUserId": 2,
"commentTime": [
"java.sql.Timestamp",
1563975495000
],
"updateTime": [
"java.sql.Timestamp",
1563975536000
],
"goodsName": "first",
"goodsId": 1,
"sellerId": 99,
"content": "this is the secount",
"title": "first",
"picPath": "string ",
"new": false
}