没被Fastjson搞过的程序员不是合格的程序员 ---- 手动狗头
开个玩笑,福报厂的同学们不要喷,Fastjson是非常优秀的工具!
复盘
先简短复盘下之前遇到的一个线上问题:随着业务发展项目A日渐臃肿,已经成为人人都头疼的big ball of mud 大泥球,遂决定对其进行重构,细节包括服务拆分与部分逻辑重构。虽然我不是这块业务的技术owner,但这类重构任务自然还是我来负责,同时在业务需求排队与原owner看戏心态的情况下,留给我从头熟悉与重构的时间并不多… 重构过程就不在这赘述了,虽然发现和解决了很多问题,但还算顺利,这中间花费时间最多的就是测试,读过老马的书或真正参与过重构的同学都知道,任何重构都建立在测试的基础上,没有单元测试、集成测试、回归测试,都是在自寻死路… 所以当我拿到项目A源码看到那空空的test文件夹时,我陷入了沉思… 但还是要硬着头皮上的,做了各种我认为有必要的测试… 时间来到了上线那一天,问题还是出现了… 问题是由新项目无法使用fastjson反序列化线上redis缓存数据导致的… 百密一疏,功亏一篑,在本地与测试环境做了N种测试,但并没考虑到线上redis缓存中还有部分老数据…
大厂的同学们都很喜欢搞脚手架,喜欢在开源工具上包装,原项目A中缓存部分就有这么一个Redis缓存脚手架工具;脚手架如果设计的好那么可以大幅提高开发效率,但如果设计的不好那对于使用者来说就是黑盒的!
这个Redis工具在序列化的时候使用json格式来做存储,使用的是Fastjson;而Fastjson在序列化Redis对象的时候,会记录class信息,所以一旦class信息对不上,那么序列化反序列化就会失败…
public class GenericFastJsonRedisSerializer implements RedisSerializer<Object> {
/** 略 */
public byte[] serialize(Object object) throws SerializationException {
if (object == null) {
return new byte[0];
}
try {
return JSON.toJSONBytes(object, SerializerFeature.WriteClassName);
} catch (Exception ex) {
throw new SerializationException("Could not serialize: " + ex.getMessage(), ex);
}
}
/** 略 */
}
虽然缓存功能也包含在测试范围内了,但不清楚这个脚手架的细节让我还是掉坑里了…
Anyway,吃一堑长一智,这就是成长啊 ---- 狗头
重现
做个最简单的demo来重新这个问题:
@SpringBootApplication
public class DemoApplication {
public static void main(String