1. 程式人生 > >Springboot+Redis序列化坑

Springboot+Redis序列化坑

今天在測試springboot整合redis的時候遇到下面這個坑,百度來百度去發現提示都是ajax的問題,真的是醉了,錯誤提示如下所示,不信大家可以直接複製百度一下答案是什麼(流淚中。。。。),錯誤如下:

org.springframework.data.redis.serializer.SerializationException: Could not read JSON: Unrecognized token 'b4811c63': was expecting ('true', 'false' or 'null')

1.錯誤原因排查

然後就進行debug除錯,發現程式碼一直到redisTemplate.opsForZSet().reverseRangeWithScores()這一行都沒問題,然後進入redis原始碼裡面檢查,發現是在傳送redis服務的時候出現問題,所以可以斷定應該是配置的問題,然後仔細檢查配置,發現也沒有錯誤,redis序列化的配置如下所示:

@Bean
public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory factory) {
    RedisTemplate redisTemplate = new StringRedisTemplate(factory);
    Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
    ObjectMapper om = new ObjectMapper();
    om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
    om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
    jackson2JsonRedisSerializer.setObjectMapper(om);
    redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);
    redisTemplate.afterPropertiesSet();
    return redisTemplate;
}

2.細節分析

這一條線索斷掉之後,只能通過錯誤資訊來分析了,錯誤資訊中有一條特別奇怪,就是token 'b4811c63',然後我仔細從redis中對比,發現是之前儲存的redis的key值,判斷可能是redis中key存在亂碼,所以就將redis的key全部清空,自己新增資料進去,發現自己新增的資料是可以的。從這一現象可以得出,應該實現老系統序列化的規則和現在springboot的序列化規則不一樣導致的,檢視老系統的redis配置資訊,如下所示:

<!--序列化-->
<bean name="stringRedisSerializer" class="org.springframework.data.redis.serializer.StringRedisSerializer"/>
<bean name="jdkSerializationRedisSerializer" class="org.springframework.data.redis.serializer.JdkSerializationRedisSerializer"/>
<bean id="clusterRedisTemplate" class="org.springframework.data.redis.core.RedisTemplate">
    <property name="connectionFactory" ref="redis4CacheConnectionFactory"/>
    <property name="keySerializer" ref="stringRedisSerializer"/>
    <property name="hashKeySerializer" ref="stringRedisSerializer"/>
    <property name="valueSerializer" ref="stringRedisSerializer"/>
    <property name="hashValueSerializer" ref="stringRedisSerializer"/>
</bean>

3.問題解決

然後和我們剛才序列化的方式對比一下,發現真的是序列化方式不一樣,舊的是通過StringRedisSerializer進行序列化的,springboot是通過Jackson2JsonRedisSerializer進行序列化的。所以為了相容老系統的序列化方式,這邊我將springboot也改成StringRedisSerializer的序列化方式,程式碼如下所示:

@Bean
public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory factory) {
    RedisTemplate redisTemplate = new StringRedisTemplate(factory);
    StringRedisSerializer stringRedisSerializer =new StringRedisSerializer();
    redisTemplate.setValueSerializer(stringRedisSerializer);
    redisTemplate.setKeySerializer(stringRedisSerializer);
    redisTemplate.setHashKeySerializer(stringRedisSerializer);
    redisTemplate.setHashValueSerializer(stringRedisSerializer);
    redisTemplate.afterPropertiesSet();
    return redisTemplate;
}

改完之後,發現這個問題就沒有了,redis中就可以照常插入、查詢資料了。

總結:

這個問題是很典型的架構優化問題,老系統和新系統程式碼相容性問題。從這個坑可以得出這樣的結論:百度得到的答案很大一部分都是片面的,我們還是得根據實際情況來分析。其次就是要仔細看報錯資訊,不要放過一點細節,因為可能你的答案就在這一點細節中。