1. fastjson使用中的常见陷阱与解决方案
fastjson作为阿里巴巴开源的Java JSON处理库,凭借其高性能和易用性在国内Java开发者中广泛流行。但在实际项目中使用fastjson时,确实存在不少容易踩坑的地方,特别是对于刚接触这个库的开发者。我在多个生产项目中深度使用fastjson后,总结了一些典型问题和解决方案。
提示:fastjson的最新稳定版本是1.2.83,但建议考虑迁移到fastjson2以获得更好的性能和安全性。
1.1 布尔类型字段的序列化问题
布尔类型字段的序列化是fastjson中最常见的坑之一。假设我们有一个简单的Java类:
java复制public class User {
private boolean isAdmin;
// getters and setters
}
当使用fastjson序列化这个对象时:
java复制User user = new User();
user.setAdmin(true);
String json = JSON.toJSONString(user);
你可能会惊讶地发现输出结果是:{"admin":true} 而不是预期的 {"isAdmin":true}。这是因为fastjson默认会去掉布尔类型字段的"is"前缀。
解决方案有三种:
- 使用@JSONField注解明确指定字段名:
java复制@JSONField(name="isAdmin") private boolean isAdmin; - 修改字段名去掉"is"前缀:
java复制private boolean admin; - 配置全局序列化特性:
java复制SerializerFeature.config(JSON.DEFAULT_GENERATE_FEATURE, SerializerFeature.WriteBooleanUseToString, true);
1.2 日期格式处理的坑
fastjson对日期类型的处理也有不少需要注意的地方。默认情况下,fastjson会将Date对象序列化为时间戳(long类型),这可能不是你想要的结果。
java复制public class Event {
private Date createTime;
// getters and setters
}
Event event = new Event();
event.setCreateTime(new Date());
String json = JSON.toJSONString(event);
// 输出类似:{"createTime":1672531200000}
要让日期以可读格式输出,可以:
- 使用@JSONField注解指定格式:
java复制@JSONField(format="yyyy-MM-dd HH:mm:ss") private Date createTime; - 全局配置日期格式:
java复制JSON.DEFFAULT_DATE_FORMAT = "yyyy-MM-dd HH:mm:ss"; - 在序列化时指定格式:
java复制String json = JSON.toJSONStringWithDateFormat(event, "yyyy-MM-dd HH:mm:ss");
注意:日期格式在不同地区可能会导致解析问题,特别是在分布式系统中,建议始终明确指定时区。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. fastjson的安全性问题与防护措施
2.1 反序列化漏洞风险
fastjson因其强大的功能而闻名,但这也带来了安全风险。最著名的就是fastjson的反序列化漏洞,攻击者可以通过精心构造的JSON字符串在反序列化时执行任意代码。
防护措施:
- 及时升级到最新版本(目前是1.2.83)
- 使用安全模式:
java复制ParserConfig.getGlobalInstance().setSafeMode(true); - 使用白名单控制可反序列化的类:
java复制ParserConfig.getGlobalInstance().addAccept("com.yourpackage.");
2.2 AutoType关闭的注意事项
fastjson的AutoType功能虽然方便,但也是安全漏洞的主要来源。从1.2.68版本开始,fastjson默认关闭了AutoType功能。
如果你确实需要AutoType功能,应该:
- 明确指定允许的类:
java复制ParserConfig.getGlobalInstance().addAccept("com.yourpackage."); - 使用hash校验:
java复制
ParserConfig.getGlobalInstance().addAcceptHash(hashCode); - 避免使用@type字段处理不可信的JSON数据
3. 性能优化与高级用法
3.1 序列化过滤与定制
fastjson提供了强大的序列化过滤功能,可以精确控制哪些字段需要序列化:
java复制SimplePropertyPreFilter filter = new SimplePropertyPreFilter(User.class, "name", "email");
String json = JSON.toJSONString(user, filter);
还可以使用PropertyFilter进行更复杂的控制:
java复制PropertyFilter filter = (object, name, value) -> {
// 自定义过滤逻辑
return !name.equals("password");
};
String json = JSON.toJSONString(user, filter);
3.2 大型JSON处理技巧
处理大型JSON文件时,可以使用流式API避免内存溢出:
java复制// 解析大型JSON文件
JSONReader reader = new JSONReader(new FileReader("large.json"));
reader.startArray();
while(reader.hasNext()) {
User user = reader.readObject(User.class);
// 处理每个user对象
}
reader.endArray();
reader.close();
// 生成大型JSON文件
JSONWriter writer = new JSONWriter(new FileWriter("large-output.json"));
writer.startArray();
for(User user : users) {
writer.writeValue(user);
}
writer.endArray();
writer.close();
3.3 与Spring Boot的集成优化
在Spring Boot项目中使用fastjson作为默认JSON处理器:
java复制@Configuration
public class WebConfig implements WebMvcConfigurer {
@Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
FastJsonHttpMessageConverter converter = new FastJsonHttpMessageConverter();
FastJsonConfig config = new FastJsonConfig();
config.setSerializerFeatures(
SerializerFeature.PrettyFormat,
SerializerFeature.WriteNullStringAsEmpty,
SerializerFeature.WriteNullNumberAsZero
);
converter.setFastJsonConfig(config);
converters.add(0, converter);
}
}
4. 从fastjson迁移到fastjson2的实践
阿里巴巴已经推出了fastjson2,它是fastjson的重大升级版本,在性能和安全性上都有显著提升。迁移过程需要注意以下几点:
4.1 API变化
fastjson2的包名从com.alibaba.fastjson改为com.alibaba.fastjson2,主要类名基本保持一致,但有一些API调整:
java复制// fastjson
JSON.parseObject(text, User.class);
// fastjson2
JSON.parseObject(text, User.class); // 相同
// 但配置方式不同
JSONFactory.setContextObjectReaderProvider(...);
JSONFactory.setContextObjectWriterProvider(...);
4.2 性能对比
fastjson2在序列化和反序列化性能上比fastjson有显著提升,特别是在处理大型对象和集合时。根据官方测试数据:
| 操作类型 | fastjson 1.2.83 | fastjson2 | 提升幅度 |
|---|---|---|---|
| 小对象序列化 | 1,200,000 ops/s | 1,800,000 ops/s | +50% |
| 大对象序列化 | 45,000 ops/s | 68,000 ops/s | +51% |
| 小对象反序列化 | 950,000 ops/s | 1,500,000 ops/s | +58% |
| 大对象反序列化 | 38,000 ops/s | 62,000 ops/s | +63% |
4.3 迁移步骤
-
替换依赖:
xml复制<!-- 移除 --> <dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>1.2.83</version> </dependency> <!-- 添加 --> <dependency> <groupId>com.alibaba.fastjson2</groupId> <artifactId>fastjson2</artifactId> <version>2.0.26</version> </dependency> -
全局搜索替换包名:
com.alibaba.fastjson→com.alibaba.fastjson2- 注意:有些类可能路径不同,需要单独处理
-
测试所有JSON处理逻辑,特别是:
- 自定义序列化/反序列化逻辑
- 日期格式处理
- 特殊类型(如枚举)的处理
-
性能测试和优化:
- 对比迁移前后的性能指标
- 根据fastjson2的新特性调整代码
5. 实际项目中的经验总结
在大型电商系统中使用fastjson处理订单数据的实践中,我总结了以下经验:
-
对于高并发接口,提前创建好ParserConfig和SerializeConfig实例并复用,避免频繁创建带来的性能开销。
-
处理数据库JSON字段时,使用TypeReference来保持泛型信息:
java复制List<OrderItem> items = JSON.parseObject( jsonStr, new TypeReference<List<OrderItem>>(){} ); -
在分布式系统中,所有服务节点应使用相同的fastjson版本和配置,避免序列化/反序列化不一致的问题。
-
对于敏感数据(如密码、token等),实现自定义的序列化器来控制这些字段的序列化行为。
-
监控fastjson的性能指标,特别是反序列化操作的耗时,及时发现潜在问题。
-
在微服务架构中,考虑在API网关层统一处理JSON的序列化配置,确保整个系统的一致性。
-
对于国际化应用,特别注意日期和数字的格式处理,避免因地区设置不同导致的问题。
-
定期检查fastjson的安全公告,及时升级到安全版本。可以考虑使用依赖检查工具(如OWASP Dependency-Check)来自动化这个过程。
