关于java:Fastjson-很快但不适合我

7次阅读

共计 4492 个字符,预计需要花费 12 分钟才能阅读完成。

作者: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 的属性上加了个注解。

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

而后就接到产品的疑难,改变呢?

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

那么当初的间接问题是:FastJson 对于工夫配置在部分的配置没有失效,应用的还是全局配置。

景象是,开发环境 Windows 上没有问题,测试环境 Linux 上呈现了问题。两者有什么区别呢?零碎问题?

既然狐疑是两个零碎导致的问题,那么就在 idea 里模仿一下 linux 零碎。在 VM options 增加 -Dos.name=linux

这不能齐全模仿 linux 零碎,只针对通过 System.getproperty("os.name") 来判断以后零碎做某些操作的时候有用。

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

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

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

因为狐疑是零碎导致的,在源码中搜寻 ’linux”unix’ 关键字,没有发现。断点整个流程重点察看了一下这部份也没有发现问题。

忽然在 JSONSerializer.dateFormatPattern上发现了这段正文。

这部份波及到了调整 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 只能放任。

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

当然,以上只是我集体的一点猜想。

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

$ref 循环援用问题

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

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

果然有很多同道中人,近 150 个问题,从工夫上来看还挺陈腐。我点击了 closed,既然敞开了,那必定解决了吧。

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

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

我感觉这也是个槽点,FastJson 如同并没有一个稳固保护的版本,遇到问题总是在降级,降级的过程中也没做好品质管制,又引入了新的问题。

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

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

我当初晓得这是因为循环援用检测引起的。通过设置 SerializerFeature.DisableCircularReferenceDetect 能够防止这个问题。

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

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

比方,以后这个循环援用在序列化会出的问题,应该是用户手动去开启,而不是默认给用户开启。在优先级上,全局应该敞开,在有循环援用的中央,让用户抉择部分开启。

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

我测试了一下,如同应用 FastJson 也并不能解析回来:

:经揭示,这里应应用残缺报文解析,经测试,的确能够。感激揭示!

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

原本是一个挺好的设计点,能起到精益求精的作用,但它却可能暴雷,这是善意办好事。

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

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

总结

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

为了写文章,那必定要去试验,得把竞品也拿进去测试一下,一测试发现并不是 FastJson 独有的,难堪!

但我还是那句话,不论你信不信,对于开源我的项目,特地是这样一个宽泛应用的开源我的项目,必定有十分值得学习的中央。一个开源我的项目,如果终日拿着显微镜去察看,那必定能找出不少故障。

这里略微总结一下本文的信息点。并不一定是某个具体 BUG, 而是通过这个 BUG,解决这个 BUG 背地所展示进去的 FastJson 的信息或趋势。

  1. reviewtestcase 笼罩不是很到位
  2. contributor 看起来很多,但重大依赖主力人员。而主力精力有限,某些优先级不那么高的 BUG 只能放任。
  3. 这个我的项目的荣誉感并没有那么高,或者叫并没有那么吸引高手)。
  4. 有些性能点应该把管制主动权交给用户,如 DisableCircularReferenceDetectWriteMapNullValue 等。默认开启非常容易导致线上暴雷。
  5. 作者曾经全面转向 fastjosn2,而且哪怕在这之前,对于 fastjson 没有一个稳固保护的版本,一直降级,一直引入新问题。

祝福 fastjson2 越来越好,不要步 struts2 的后尘。

近期热文举荐:

1.1,000+ 道 Java 面试题及答案整顿(2022 最新版)

2. 劲爆!Java 协程要来了。。。

3.Spring Boot 2.x 教程,太全了!

4. 别再写满屏的爆爆爆炸类了,试试装璜器模式,这才是优雅的形式!!

5.《Java 开发手册(嵩山版)》最新公布,速速下载!

感觉不错,别忘了顺手点赞 + 转发哦!

正文完
 0