Fastjson 很快,但不适合我....

简介: Fastjson 很快,但不适合我....

作者:nyingping

来源:juejin.cn/post/7215886869199863869


记者:大爷您有什么特长呀?


FastJson:我很快。


记者:23423 乘以 4534 等于多少?


FastJson:等于 2343.


记者:??


FastJson:你就说快不快吧!


这个略显马丽苏的标题,各位看官将就着看吧。主要是怕被喷。FastJson 真的很好,我用不用我喜不喜欢的,太不重要了,我只是觉得不适合我而已。


话说以前 Gson 用得好好的,同事极力推荐我使用 FastJson,说很快云云。尽管我们的系统根本感知不出来这点速度差异。


之前也听说 FastJson 爆出来什么重大漏洞,但对我们基本没什么影响,所以这一点倒是没什么偏见。


然后在一个新项目上,脑抽抽,把 Gson 换成了 FastJson,Spring Boot 默认支持的 Jackson 换成了 FastJson。


然后就开始遇到了一些问题。先声明,这真不是尬黑,为了文章效果,故意网上扒些黑料拼凑起来,本文所提到的问题,都来源于本人最近项目的真实经历。


推荐一个开源免费的 Spring Boot 最全教程:


https://github.com/javastacks/spring-boot-best-practice


dateformat 优先级

本来是一个风和日丽的下午,一个非常简单的改动需求。接口返回的时间只需要年月日日期类型不需要时分秒。因为我配置全局时间格式化为yyyy-MM-dd HH:mmss,于是我愉快的在 javabean 的属性上加了个注解。


54a738c3827cc71e5fbb4184d744bde2_4280b2d1846c445fb4b866fafd687fde.png


本地测试一下,没问题,提交到测试环境,搞定,完美。


然后就接到产品的疑问,改动呢?


我登上去看了一下,唉,没改到啊,日期还是带了时分秒。我大意了啊,这么小的改动,又是在测试环境,就没加验证。


那么现在的直接问题是:FastJson 关于时间配置在局部的配置没有生效,使用的还是全局配置。


现象是,开发环境 Windows 上没有问题,测试环境 Linux 上出现了问题。两者有什么区别呢?系统问题?


既然怀疑是两个系统导致的问题,那么就在 idea 里模拟一下 linux 系统。在 VM options 添加 -Dos.name=linux


这不能完全模拟 linux 系统,只针对通过System.getproperty("os.name")来判断当前系统做某些操作的时候有用。


通过这种方式没复现,我又想到了远程调试。


一阵操作猛如虎,远程调试倒是能进断点,只是断点进不了第三方 jar 包的源码。等于白搞。


得,还是回到源码吧。拉下源码,断点,观察 JSONSerializer 类,主要是writeWithFormat方法。没有发现问题。


因为怀疑是系统导致的,在源码中搜索'linux''unix'关键字,没有发现。断点整个流程重点观察了一下这部份也没有发现问题。


突然在 JSONSerializer.dateFormatPattern上发现了这段注释。


b6948c41a990948d36772358abc6b7c0_dd11cf5e4a41469f8ca2cda51c7188be.png


这部份涉及到了调整 dateformat 的问题,重点在这个#1868,这通常是 github 的问题编号。


1.对于开源项目来说,解决了 BUG,通常会把问题编号放到注释里面去。前提是注释有必要。通过问题编号可以看到问题的前因后果。


2.通常来说,对于 github 开源项目都有 issue 区,拿着这个到编号直接到 issue 一搜就能搜到。


3.但也有一些项级项目,如 spark,flink 是没有 issue 区的,它们的类型问题发现描述追踪都使用 jira 平台。如:


https://issues.apache.org/jira/browse/SPARK-38349


在提交 PR 的时候标题也严格按照[jira 编号][spark 子模块(如core/sql) title]的规则来。


所以拿着这个编号到issue区,不管有没有issue区,也都可以直接到pullrequest区直接搜索,就算 PR 标题里没有问题编号,PR 描述肯定也是有的,只要是有严格 PR 流程的开源项目。


所以这个问题在这里:


https://github.com/alibaba/fastjson/issues/1868


相应的 PR 在这里:


https://github.com/alibaba/fastjson/pull/2706


通过 ISSUES 描述的已知信息,可以看出他遇到的问题跟我是一样的,而这个问题早在 2018 年就提出了。但问题描述不太专业,没有涉及到环境以及最重要的 FastJson 的版本问题。


而通过 PR 可知,这个问题最终在 2020 才解决,期间仅在 ISSUES 区提出的相同问题就有 #1868 #1968 #2029 #24524 个。


解决问题的版本为:1.2.72.


这个信息很关键。我对照了我开发环境的版本,是高于 1.2.72 的,所以没有出现测试环境的问题。


所以,柯南告诉我们,排除了所有可能性,剩下的哪怕再可笑,也是最终问题所在。


那就是,测试环境所用的 FastJson 版本是低于 1.2.72 的。


这种可能性是存在的,因为我们用的是 maven 打代码包,依赖包单独存在。


我最终在测试环境的依赖包目录下发现了两个 Fastjson 包,果然不出所料,有一个 1.2.53 的低版本,它就是罪魁祸首。


所以,最终这个问题有相当大的程度是由于我们团队自身问题引发的。但通过解决这个问题的过程也发现了一些有意思的情况。


首先,FastJson 在某一个版本为什么会引发这个问题。它肯定是某个 PR 改出问题的,rv,testcase 覆盖没有到位。


其次,从试图解决这个问题的 3 个 PR 的时间线,分别在 2018 年,2019 年,2020 年。说明,FastJson 这个项目的 contributor 看起来有百来人,但其中过于依赖其中某 1 个或者某些主力人员。精力有限,某些优先级不那么高的 BUG 只能放任。

7e5605fce1370043db875842766d098c_ec8d822f26d045df98b91c8a055073c7.png



同时这个项目的荣誉感并没有那么高(或者叫并没有那么吸引高手),它并不是 Apache 顶级项目,要是其它诸如 Spark、Flink、Spring,哪怕是 Dubbo 呢,很想象这些项目会有一个并不算复杂的 BUG 悬而未决长达 3 年时间。在这些顶级开源项目,大家都是拼了老命的想找些 BUG 来提交 PR。


当然,以上只是我个人的一点猜测。


复盘,遇到 FastJson 的问题,一开始就应该奔着 github 的 issues 区,它大概率已经被前人踩坑了。


$ref 循环引用问题


e93277332c42299cff7a33c20e8fe216_012f118282bb44b99ab52f531078d0f4.png

以上测试接口返回前端什么?


62842f85678c99c7c983a3561fd2d1aa_2bbf6cc802fb42f1a70c58c1a3abfbd7.png


我现在并不知道什么循环引用检测,这时候它是我的知识盲区。此时,我观察到的现象是,young和children两个 list 对象中均引用指向了王麻子这个对象。然后,在第 2 次children引用的时候它在序列化的时候直接指向了第 1 个young里相应对象引用。当然遇到这个问题的时候,我在仔细观察排除了非 fastjson 的问题以后,这次我学聪明了,我直接来到了 Github 的 issues 区,搜索$ref。



b16c9070002c38e204958e6ac77f5d37_da18abc8d608480caed8f4f676b6b891.png

果然有很多同道中人,近 150 个问题,从时间上来看还挺新鲜。我点击了 closed,既然关闭了,那肯定解决了吧。


我点进了 closed 区第一个问题,然后作者让升级到 fastjson2。???


6aa784dae3d8b017f15c315e73b824e1_23a1bf039bd540f796315c30133a27a3.png


如果我没有理解错,FastJson 和 FastJson2 可不是两个版本的区别,是两个项目也!据说 API 也有兼容性问题。直接这样升级过去,谈何容易!


我觉得这也是个槽点,FastJson 好像并没有一个稳定维护的版本,遇到问题总是在升级,升级的过程中也没做好质量控制,又引入了新的问题。


还是在当前项目寻求解决方法吧,哪怕升版本也好啊。终于在另一个问题下面找到了问题所在以及解决方案。


https://github.com/alibaba/fastjson/issues/3643


我现在知道这是由于循环引用检测引起的。通过设置SerializerFeature.DisableCircularReferenceDetect可以避免这个问题。


但是,我的代码其实并没有循环引用啊,只是两个子对象引用了同一个对象而已。这算什么?误伤吗?


更重要的,一些控制权应该在使用者手里?


比如,当前这个循环引用在序列化会出的问题,应该是用户手动去开启,而不是默认给用户开启。在优先级上,全局应该关闭,在有循环引用的地方,让用户选择局部开启。


现在我的前端并没有使用 FastJson,面对"$ref":"$.result.young[1]"这种文本,它能解析吗?它不能呀。


我测试了一下,好像使用 FastJson 也并不能解析回来:

625b57878053d3dc49dca11696bb49a2_d0e034c5f7764a3e94b9b54831218266.png



注 :经提醒,这里应使用完整报文解析,经测试,确实可以。感谢提醒!


更可怕的问题是,刚好在测试环节有两个子对象引用了同一个对象,被我提前发现了。如果测试环境没有这样的情况,在生产环境刚好遇到了呢?那就是生产事故了呀。


本来是一个挺好的设计点,能起到锦上添花的作用,但它却可能暴雷,这是好心办坏事。


同样的,还有SerializerFeature.WriteMapNullValue。如果一个字段值为null,fastjson 默认就不返回该字段了。本来前后端约定好,如果为null就怎样处理的逻辑,可能在生产环境中突然暴雷啊。


就像WriteNullListAsEmpty就很好,不错的设计点,如果返回的 list 为null的时候,用户可以选择让它序列化为[],但它也不是默认开启的呀,给了用户额外的选择权,对吧。


总结

写到这里的时候,我是真心觉得 FastJson 有比竞品有些特色的地方。这真不是为了所谓的客观公正,非要负面写多点,再搞点正面的。


为了写文章,那肯定要去试验,得把竞品也拿出来测试一下,一测试发现并不是 FastJson 独有的,尴尬!


但我还是那句话,不管你信不信,对于开源项目,特别是这样一个广泛使用的开源项目,肯定有非常值得学习的地方。一个开源项目,如果整天拿着显微镜去观察,那肯定能找出不少毛病。


这里稍微总结一下本文的信息点。并不一定是某个具体 BUG,而是通过这个 BUG,解决这个 BUG 背后所展现出来的 FastJson 的信息或趋势。


review,testcase 覆盖不是很到位

contributor 看起来很多,但严重依赖主力人员。而主力精力有限,某些优先级不那么高的 BUG 只能放任。

这个项目的荣誉感并没有那么高,或者叫并没有那么吸引高手)。

有些功能点应该把控制主动权交给用户,如 DisableCircularReferenceDetect,WriteMapNullValue 等。默认开启非常容易导致线上暴雷。

作者已经全面转向 fastjosn2,而且哪怕在这之前,对于 fastjson 没有一个稳定维护的版本,不断升级,不断引入新问题。

————————————————

版权声明:本文为CSDN博主「Java技术栈」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。

原文链接:https://blog.csdn.net/youanyyou/article/details/130879651

相关文章
|
JSON 算法 安全
不破不立!Fastjson2.0 性能炸裂,为了下一个十年
Alibaba Fastjson: 目前在人类已知范围内,这个星球跑的最快的Java JSON库。在过去的十年里,fastjson v1作为国内github star最多和最受欢迎的json解析库,如今fastjson v2 重磅来袭,性能炸裂。
16650 2
不破不立!Fastjson2.0 性能炸裂,为了下一个十年
|
3月前
|
前端开发 fastjson Java
我的字段被FastJson给干掉了?!
本文记录作者升级到 JDK 11 后遇到的 FastJSON 序列化问题,以及详细的排查过程。
122 12
|
1月前
|
存储 JSON fastjson
再也不用心惊胆战地使用FastJSON了——序列化篇
本篇将主要介绍json序列化的详细流程。本文阅读的FastJSON源码版本为2.0.31。
|
JSON fastjson Java
下个十年高性能 JSON 库来了:fastjson2!
下个十年高性能 JSON 库来了:fastjson2!
1427 0
|
7月前
|
JSON fastjson Java
fastjson是什么东西,怎么用?
fastjson是什么东西,怎么用?
|
分布式计算 JavaScript 前端开发
Fastjson 很快,但不适合我....
Fastjson 很快,但不适合我....
Fastjson 很快,但不适合我....
|
JSON JavaScript fastjson
深入探索FastJSON:高效的JSON处理工具
在现代的应用开发中,JSON(JavaScript Object Notation)作为一种轻量级的数据交换格式被广泛使用。FastJSON作为一款高性能的JSON处理工具,在Java应用中得到了广泛的应用。本文将深入探讨FastJSON的基本概念、特点,以及如何在实际应用中使用它进行高效的JSON数据处理。
560 0
|
JSON fastjson 数据格式
震惊!fastjson SerializerFeature详解竟然是这个样子
震惊!fastjson SerializerFeature详解竟然是这个样子
283 0
震惊!fastjson SerializerFeature详解竟然是这个样子
|
JSON fastjson 数据格式
FastJson 我大意了,我没有闪
FastJson 我大意了,我没有闪
216 0
FastJson 我大意了,我没有闪
|
JSON 缓存 安全
大型项目废弃fastjson迁移至Gson保姆级攻略
本篇文章是我这一个多月来帮助组内废弃fastjson框架的总结,我们将大部分Java仓库从fastjson迁移至了Gson。 这么做的主要的原因是公司受够了fastjson频繁的安全漏洞问题,每一次出现漏洞都要推一次全公司的fastjson强制版本升级,很令公司头疼。 文章的前半部分,我会简单分析各种json解析框架的优劣,并给出企业级项目迁移json框架的几种解决方案。 在文章的后半部分,我会结合这一个月的经验,总结下Gson的使用问题,以及fastjson迁移到Gson踩过的深坑。
481 0