我将Redis用作Spring Boot 2应用程序中的缓存存储。我在某些方法中使用了@Cacheable
注释,我想将数据作为非类型化JSON存储在Redis中。使用当前的我的配置,保存数据可以正常工作,但是读取它会生成ClassCastException
。
所有解决方案,答案,示例和教程均使用Jackson的ObjectMapper
来配置RedisTemplate
或RedisCacheConfiguration
,以向JSON添加默认的输入属性。这里的事情是,该缓存将由不同语言/技术的不同应用共享,而我不能强迫其余应用像Spring Boot一样工作。
这就是我现在拥有的:
配置
@Bean
CacheManager cacheManager(RedisConnectionFactory connectionFactory) {
return RedisCacheManagerBuilder.fromConnectionFactory(connectionFactory)
.cacheDefaults(cacheConfiguration())
.build();
}
private RedisCacheConfiguration cacheConfiguration() {
return RedisCacheConfiguration.defaultCacheConfig()
.disableCachingNullValues()
.serializeKeysWith(SerializationPair.fromSerializer(RedisSerializer.string()))
.serializeValuesWith(SerializationPair.fromSerializer(new GenericJackson2JsonRedisSerializer(redisMapper())));
}
private ObjectMapper redisMapper() {
return new ObjectMapper()
//.enableDefaultTyping(DefaultTyping.NON_FINAL, As.PROPERTY)
.setSerializationInclusion(JsonInclude.Include.NON_EMPTY);
}
服务
@Cacheable(key = "'persons::' + #id")
public Person getPerson(Long id) {
// return person from DB
}
使用当前配置的结果:
{
"name": "John",
"lastName": "Doe",
"age": 31
}
当Spring尝试使用反序列化器从缓存中读取内容时,找不到带有类型信息的"@class"
属性,因此它返回LinkedHashMap
。之后,CacheInterceptor
尝试将LinkedHashMap
转换为Person
,并出现ClassCastException
发生的时间。
Request processing failed; nested exception is java.lang.ClassCastException: java.util.LinkedHashMap cannot be cast to com.test.dto.Person
这时我可以,如果我需要为要存储的每种类型编写一个序列化程序,或者可以为所有类型创建一个自定义序列化程序。到目前为止,我的研究尚未成功。
感谢您的时间。
答案 0 :(得分:0)
老实说,我不确定这是否是您的问题的答案,因为它没有创建像您的示例那样的“干净”和“漂亮”的JSON,但是它对我来说可以序列化和反序列化。在此示例中,缓存管理器设置为TTL,您可以根据需要将其删除。
@Configuration
@EnableCaching
public class RedisCacheConfig {
@Value("${spring.redis.host}")
private String redisHostName;
@Value("${spring.redis.port}")
private int redisPort;
@Bean
public LettuceConnectionFactory redisConnectionFactory() {
return new LettuceConnectionFactory(new RedisStandaloneConfiguration(redisHostName, redisPort));
}
@Bean
public RedisTemplate<Object, Object> redisTemplate() {
RedisTemplate<Object, Object> redisTemplate = new RedisTemplate<Object, Object>();
redisTemplate.setConnectionFactory(redisConnectionFactory());
return redisTemplate;
}
@Bean
@Primary
public RedisCacheManager redisCacheManager(LettuceConnectionFactory lettuceConnectionFactory) {
RedisCacheConfiguration redisCacheConfiguration = RedisCacheConfiguration.defaultCacheConfig().disableCachingNullValues()
.entryTtl(Duration.ofMinutes(1))
.serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(RedisSerializer.json()));
redisCacheConfiguration.usePrefix();
return RedisCacheManager.RedisCacheManagerBuilder.fromConnectionFactory(lettuceConnectionFactory)
.cacheDefaults(redisCacheConfiguration).build();
}
}