作者: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 回圈參考問題

以上測驗介面回傳前端什么?

我現在并不知道什么回圈參考檢測,這時候它是我的知識盲區,此時,我觀察到的現象是,young和children兩個 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 的資訊或趨勢,
review,testcase覆寫不是很到位contributor看起來很多,但嚴重依賴主力人員,而主力精力有限,某些優先級不那么高的 BUG 只能放任,- 這個專案的榮譽感并沒有那么高,或者叫并沒有那么吸引高手),
- 有些功能點應該把控制主動權交給用戶,如
DisableCircularReferenceDetect,WriteMapNullValue等,默認開啟非常容易導致線上暴雷,- 作者已經全面轉向 fastjosn2,而且哪怕在這之前,對于 fastjson 沒有一個穩定維護的版本,不斷升級,不斷引入新問題,
祝愿 fastjson2 越來越好,不要步 struts2 的后塵,
近期熱文推薦:
1.1,000+ 道 Java面試題及答案整理(2022最新版)
2.勁爆!Java 協程要來了,,,
3.Spring Boot 2.x 教程,太全了!
4.別再寫滿屏的爆爆爆炸類了,試試裝飾器模式,這才是優雅的方式!!
5.《Java開發手冊(嵩山版)》最新發布,速速下載!
覺得不錯,別忘了隨手點贊+轉發哦!
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/553509.html
標籤:其他
上一篇:JavaWeb編程面試題——Spring Web MVC
下一篇:返回列表
