我在 Spring Boot 2 应用程序中使用 Redis 作为缓存存储。我在某些方法中使用 @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
此时,如果我需要为我想要存储的每种类型编写一个序列化器,或者我可以为所有类型创建一个自定义序列化器,我就可以了。到目前为止我的研究还没有成功。
感谢您的宝贵时间。
最佳答案
老实说,我不确定这是否是您问题的答案,因为它不会像您的示例那样创建如此“干净”和“美丽”的 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();
}
}
关于json - 如何使用 Spring Boot 2 CacheManager 在 Redis 中存储非类型化 JSON,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56637032/