如何使用Spring Boot 2 CacheManager在Redis中存储非类型的JSON

时间:2019-06-17 18:35:53

标签: json spring spring-boot caching redis

我将Redis用作Spring Boot 2应用程序中的缓存存储。我在某些方法中使用了@Cacheable注释,我想将数据作为非类型化JSON存储在Redis中。使用当前的我的配置,保存数据可以正常工作,但是读取它会生成ClassCastException

所有解决方案,答案,示例和教程均使用Jackson的ObjectMapper来配置RedisTemplateRedisCacheConfiguration,以向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

这时我可以,如果我需要为要存储的每种类型编写一个序列化程序,或者可以为所有类型创建一个自定义序列化程序。到目前为止,我的研究尚未成功。

感谢您的时间。

1 个答案:

答案 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();

  }
}