GenericJackson2JsonRedisSerializer 的时间序列化问题

GenericJackson2JsonRedisSerializer 是 Spring Data Redis 包提供的一个类,用于将 Java 对象与 JSON 字符串进行转换,存储于 Redis 时是 JSON,取出来时转换为 Java 对象。

该类是用于设置 RedisTemplate 的序列化器时一般这样配置:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
private RedisTemplate<Object, Object> createGenericRedisTemplate(RedisConnectionFactory redisConnectionFactory) {
RedisTemplate<Object, Object> redisTemplate = new RedisTemplate<>();

redisTemplate.setKeySerializer(new StringRedisSerializer());

redisTemplate.setHashKeySerializer(new StringRedisSerializer());


redisTemplate.setValueSerializer(new GenericJackson2JsonRedisSerializer());
redisTemplate.setHashValueSerializer(new GenericJackson2JsonRedisSerializer());
redisTemplate.setDefaultSerializer(new GenericJackson2JsonRedisSerializer());

redisTemplate.setConnectionFactory(redisConnectionFactory);
return redisTemplate;
}

这个配置一般用起来是没问题的,但很快你会发现一些理所当然的配置会不生效。

1
2
3
4
spring:
jackson:
date-format: "yyyy-MM-dd HH:mm:ss"
time-zone: "Asia/Shanghai"

上面这个配置用于配置 Jackson 的 JSON 时间格式和时区的,但对 RedisTemplate 里取到的时间好像没有效果。实际上,虽然 GenericJackson2JsonRedisSerializer 类有 Jackson 字样,但是实际上不是 Jackson 里的内容,这里只是表示用 Jackson 来处理 JSON 格式化而已,Jackson 的自动配置并不会在该类中生效。

GenericJackson2JsonRedisSerializer 的实现中可以知道,如果不传入 Jackson 的 ObjectMapper,内部会创建一个使用默认配置的 ObjectMapper。 自动配置的 Jackson 和这个 ObjectMapper 的配置是没有关系的。

当然我们可以用注入的方式取到 ObjectMapper 并配置到 GenericJackson2JsonRedisSerializer Bean 中,但这里同样有个问题。因为注入的 ObjectMapper 中自动配置通用的,是全局都用的对象。GenericJackson2JsonRedisSerializer 里是需要对 ObjectMapper 进行一些配置的,比如将原始的类型信息写入 到 @class 的属性中,这里不应该修改通用的 ObjectMapper。

分析到这里,其实也可以知道,我们只需要创建一新的 ObjectMapper 并注入配置。

1
2
3
4
5
6
7
8
9
10
11
private ObjectMapper createGenericObjectMapper() {
final ObjectMapper objectMapper = new ObjectMapper();

objectMapper.setTimeZone(jacksonProperties.getTimeZone());

objectMapper.registerModule(new SimpleModule().addSerializer(new NullValueSerializer(null)));

objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL, JsonTypeInfo.As.PROPERTY);

return objectMapper;
}