Redian新闻
>
Fastjson 很快,但不适合我....

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

公众号新闻

点击上方“芋道源码”,选择“设为星标

管她前浪,还是后浪?

能浪的浪,才是好浪!

每天 10:33 更新文章,每天掉亿点点头发...

源码精品专栏

 
来源:juejin.cn/post/
7215886869199863869

大意了

记者:大爷您有什么特长呀?fastjson:我很快。记者:25乘以23等于多少?fastjson:等于88。记者:??fastjson:你就说快不快吧!

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

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

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

然后在一个新项目上,脑抽抽,把gson换成了fastjson,还把spring boot默认支持的jackson换成了fastjson。

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

dateformat优先级

本来是一个风和日丽的下午,一个非常简单的改动需求。接口返回的时间只需要年月日日期类型不需要时分秒。

因为我配置全局时间格式化为yyyy-MM-dd HH:mmss,于是我愉快的在javabean的属性上加了个注解。

@JSONField(format="yyyy-MM-dd")

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

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

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

大意了

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

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

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

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

通过这种方式没复现。

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

得,还是回到源码吧。拉下源码,断点,观察JSONSerializer类,主要是writeWithFormat方法。没有发现问题。因为怀疑是系统导致的,在源码中搜索'linux''unix'关键字,没有发现。断点整个流程重点观察了一下这部份也没有发现问题。

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

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只能放任。

fastjson

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

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

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

基于 Spring Boot + MyBatis Plus + Vue & Element 实现的后台管理系统 + 用户小程序,支持 RBAC 动态权限、多租户、数据权限、工作流、三方登录、支付、短信、商城等功能

  • 项目地址:https://github.com/YunaiV/ruoyi-vue-pro
  • 视频教程:https://doc.iocoder.cn/video/

$ref循环引用问题

public ResultBody test () {
        List<Person> list = new ArrayList<>();
        Person obj1 = new Person("张三"48);
        list.add(obj1);

        Person obj2 = new Person("李四"23);
        list.add(obj2);

        Person obj3 = new Person("王麻子"17);
        list.add(obj3);

        List<Person> young = list.stream().filter(e -> e.getAge() <= 45).collect(Collectors.toList());
        List<Person> children =  list.stream().filter(e -> e.getAge()< 18).collect(Collectors.toList());

        HashMap map = new HashMap();
        map.put("young", young);
        map.put("children", children);

        return ResultBody.success(map);
        }

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

{
        "code":"200",
        "message":"成功!",
        "result":{
        "young":[
        {
        "age":23,
        "name":"李四"
        },
        {
        "age":17,
        "name":"王麻子"
        }
        ],
        "children":[
          {"$ref":"$.result.young[1]"}
        ]
        }
        }

我现在并不知道什么循环引用检测,这时候它是我的知识盲区。此时,我观察到的现象是,youngchildren两个list对象中均引用指向了王麻子这个对象。然后,在第2次children引用的时候它在序列化的时候直接指向了第1个young里相应对象引用。

当然遇到这个问题的时候,我在仔细观察排除了非fastjson的问题以后,这次我学聪明了,我直接来到了github的issues区,搜索$ref

循环引用检测

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

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

fastjson2

连 fastjson 原作者都抛弃了 fastjson 了,哎,开源真难!

如果我没有理解错,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的时候,用户可以选择让它序列化为[],但它也不是默认开启的呀,给了用户额外的选择权,对吧。

基于 Spring Cloud Alibaba + Gateway + Nacos + RocketMQ + Vue & Element 实现的后台管理系统 + 用户小程序,支持 RBAC 动态权限、多租户、数据权限、工作流、三方登录、支付、短信、商城等功能

  • 项目地址:https://github.com/YunaiV/yudao-cloud
  • 视频教程:https://doc.iocoder.cn/video/

总结

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

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

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

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

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

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

你们看好fastjson2吗


欢迎加入我的知识星球,一起探讨架构,交流源码。加入方式,长按下方二维码噢

已在知识星球更新源码解析如下:

最近更新《芋道 SpringBoot 2.X 入门》系列,已经 101 余篇,覆盖了 MyBatis、Redis、MongoDB、ES、分库分表、读写分离、SpringMVC、Webflux、权限、WebSocket、Dubbo、RabbitMQ、RocketMQ、Kafka、性能测试等等内容。

提供近 3W 行代码的 SpringBoot 示例,以及超 4W 行代码的电商微服务项目。

获取方式:点“在看”,关注公众号并回复 666 领取,更多内容陆续奉上。

文章有帮助的话,在看,转发吧。

谢谢支持哟 (*^__^*)

微信扫码关注该文公众号作者

戳这里提交新闻线索和高质量文章给我们。
相关阅读
“很快走红”又“很快消失”的品牌,做错了什么?WestJet飞行员罢工已避免!廉价航空Swoop或将终结!读澳洲幼教1年课程就能移民?选之前先看清楚适合不适合你!找到了最适合我的工作心动吗?新西兰人去澳洲上班,收入立马翻番!上两周休两周,但不适合所有人...基辛格:迫使中国解体不符合我们的利益很快,悉尼将有大事!关系华人买房,自建房!盛大展会向公众开放,只需免费提前注册!使用 fastjson 又又又翻车了,“莫名其妙”多了属性!喜新厌旧Next.js + Rust 革新全栈开发,Rust没那么难关于A-Level课程的十万个为什么:选课、AS、A2、学科难度、哪个适合我......每日原则:某个人“不适合某个岗位”时,要考虑是否有更适合他的空缺,还是你需要让他们离开公司扯白|| “不破不立”的快意人生,可能不适合所有人关于前后端JSON解析差异问题与思考“卖家说刘德华的脸更适合我”!想换谁的就换谁的,1.5万元包学会…AI变脸该如何鉴别?联影医疗 2022年及2023年一季报点评:业绩符合我们预期,看好国内外市场稳步推进【东吴医药朱国广团队】【经济】很快,法国网络银行将不再全免卡费?爱裸奔ML的合租情侣联合我ex在客厅染恶习还排挤我搬家未来三天Westjet航空国内国际航班或被取消!大家出行注意吴妈,我要困觉”,演绎不成维娜斯之塑。“死故应尓”的下一步,可能导致“人彘”。大多数的“中华民族传统美德”,往往正在这个质量水平(古詩詞英譯) 早梅 - (明)道源很快,美国伟哥可以不用处方随意买!首款新药刚获批,10分钟起效JSON 将替代 XML?绝对不可能!春假在即,“最适合带娃”城市榜单出炉 | 拉斯维加斯竟上榜,而这个城市最不适合!柏林工大也有自己的Döner店了!微信键盘全平台体验:最适合微信的输入法,但不适合所有人5037 血壮山河之武汉会战 鏖战幕府山 6很快,坐飞机就可以用5G上网了。注意!WestJet将关闭Sunwing航空公司,将其并进主线业务陌上花开961 愿有岁月可回首,且以深情共白头 | 人大,ESTJ,书迷选课、AS、A2、学科难度,A-Level课程适合我吗?迪士尼里最适合我扮演的角色!很符合我的精神状态和我人生态度探究|Go JSON 三方包哪家强?《喀秋莎》
logo
联系我们隐私协议©2024 redian.news
Redian新闻
Redian.news刊载任何文章,不代表同意其说法或描述,仅为提供更多信息,也不构成任何建议。文章信息的合法性及真实性由其作者负责,与Redian.news及其运营公司无关。欢迎投稿,如发现稿件侵权,或作者不愿在本网发表文章,请版权拥有者通知本网处理。