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

标签 json spring spring-boot caching redis

我在 Spring Boot 2 应用程序中使用 Redis 作为缓存存储。我在某些方法中使用 @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

此时,如果我需要为我想要存储的每种类型编写一个序列化器,或者我可以为所有类型创建一个自定义序列化器,我就可以了。到目前为止我的研究还没有成功。

感谢您的宝贵时间。

最佳答案

老实说,我不确定这是否是您问题的答案,因为它不会像您的示例那样创建如此“干净”和“美丽”的 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/

相关文章:

javascript - 将字符串数据转为json格式

java - Spring Integration SFTP 上传非 XML 配置

Spring boot 1.5.9,访问 Docker 容器中的资源镜像时出现 404 错误

java - 带有实体类的 NullPointerException

java - 设置springboot启动检查redis,database,mq

javascript - 在嵌套循环中从 $.get() 返回数组

javascript - 如何在谷歌浏览器扩展中引用版本信息?

javascript - 使用 Gulp 读取、重建和替换文件中的内容 block 的最有效方法是什么?

java - 无法使用提供的颁发者 "https://login.microsoftonline.com/xxxxx/.well-known/openid-configuration"解析 OpenID 配置

java.lang.IllegalArgumentException : Cannot find a factory to create the request context