springboot⽤redis缓存整合springcache注解,使⽤Json序列化和反序列化。springboot下⽤cache注解整合redis并使⽤json序列化反序列化。
cache注解整合redis
最近发现spring的注解⽤起来真的是很⽅便。随即产⽣了能不能吧spring注解使⽤redis实现的⽅式。
只需要在配置⽂件中(application.propertoes)添加如下⼀个配置
pe=redis
并配置好redis的相关信息
springcache注解整合redis⾮常容易就整合完成了。
redis缓存序列化与反序列化
由于缓存数据使⽤的是jdk⾃带的序列化需要序列化的实体类继承Serializable接⼝。⽽且序列化后的内容在redis中看起来也不是很⽅便。
于是萌⽣了需要将数据序列化成json的想法。
经过⼀番研究后决定写⼀个redis 配置⽂件。RedisConfig具体内容如下
@Configuration
public class RedisConfig extends CachingConfigurerSupport {
@Bean
public RedisCacheConfiguration redisCacheConfiguration(){
Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<>(Object.class);
RedisCacheConfiguration configuration = RedisCacheConfiguration.defaultCacheConfig();
configuration = configuration.serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(jackson2JsonRedisSerializer)).entryTtl(Duration.ofDays(30));
return configuration;
}
@Bean
public CacheManager cacheManager(RedisConnectionFactory connectionFactory) {
//初始化⼀个RedisCacheWriter
RedisCacheWriter redisCacheWriter = LockingRedisCacheWriter(connectionFactory);
//设置CacheManager的值序列化⽅式为 fastJsonRedisSerializer,但其实RedisCacheConfiguration默认使⽤StringRedisSerializer序列化key,
Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<>(Object.class);
RedisSerializationContext.SerializationPair<Object> pair = RedisSerializationContext.SerializationPair.fromSerializer(jackson2JsonRedisSerializer);
RedisCacheConfiguration defaultCacheConfig=RedisCacheConfiguration.defaultCacheConfig().serializeValuesWith(pair);
return new RedisCacheManager(redisCacheWriter, defaultCacheConfig);
}
}
配置完成后,数据访问序列化都⾮常正常,redis中也可以看到有序的json数据。
{
"name": "long",
"age": 18,
"height": 1.72
}
但是。。。。
当再次访问时出现了⼀个奇怪的问题。
LinkedHashMap 不能转换为实体类。
java.lang.ClassCastException: java.util.LinkedHashMap cannot be cast to com.ity.User
这看起来很像泛型丢失啊。
随即第三版配置⽂件出炉了,配置⼀下序列化的泛型保存
@Configuration
public class RedisConfig extends CachingConfigurerSupport {
@Bean
public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory factory) {
RedisTemplate<Object, Object> redisTemplate = new RedisTemplate<>();
redisTemplate.setConnectionFactory(factory);
Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
MyObjectMapper objectMapper = new MyObjectMapper();
objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
jackson2JsonRedisSerializer.setObjectMapper(objectMapper);
redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);
redisTemplate.setKeySerializer(new StringRedisSerializer());
redisTemplate.afterPropertiesSet();
return redisTemplate;
}
@Bean
public CacheManager cacheManager(RedisConnectionFactory factory) {
RedisSerializer<String> redisSerializer = new StringRedisSerializer();
Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
MyObjectMapper objectMapper = new MyObjectMapper();
objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
jackson2JsonRedisSerializer.setObjectMapper(objectMapper);
// 配置序列化
RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig();
RedisCacheConfiguration redisCacheConfiguration = config.serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(redisSerializer)).serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(jackson2 return RedisCacheManager.builder(factory).cacheDefaults(redisCacheConfiguration).build();
}
private class MyObjectMapper extends ObjectMapper {
private static final long serialVersionUID = 1L;
public MyObjectMapper() {
super();
// 去掉各种@JsonSerialize注解的解析
// 只针对⾮空的值进⾏序列化
this.setSerializationInclusion(JsonInclude.Include.NON_NULL);
// 将类型序列化到属性json字符串中
// 对于不到匹配属性的时候忽略报错
// 不包含任何属性的bean也不报错
}springboot aop
}
}
好了这下反序列化的问题解决了,
redis中
[
"com.ity.User",
{
"name": "long",
"age": 18,
"height": 1.72
}
]
redis存储的json中带上了类型
⾄此这个问题就解决了。
后记
在愉快使⽤缓存注解的时候,发现缓存注解并不能和诸如事务注解线程池注解⼀起使⽤。这是aop代理的特性决定的。⽽且⽅法的类内部调⽤也不⾛注解。enableDefaultTyping 这个功能涉及到java著名的反序列化漏洞。各位系统之间调⽤数据的项⽬还是慎重使⽤.
后记的后记
在写代码的过程中发现了⼀个更优雅的解决⽅案分享给⼤家。
只需要在配置⽂件中配置⼀下CacheManger,使⽤jackson的⼀个带泛型的序列化⼯具实现。
/**
* spring cache 注解相关序列化操作
*/
@Bean
public CacheManager cacheManager(RedisConnectionFactory factory) {
GenericJackson2JsonRedisSerializer genericJackson2JsonRedisSerializer = new GenericJackson2JsonRedisSerializer();
StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
// 配置序列化
RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig();
RedisCacheConfiguration redisCacheConfiguration = config
// 键序列化⽅式 redis字符串序列化
.serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(stringRedisSerializer))
// 值序列化⽅式简单json序列化
.serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(genericJackson2JsonRedisSerializer));
return RedisCacheManager.builder(factory).cacheDefaults(redisCacheConfiguration).build();
}
⼤佬的启发
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论