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