FastJson是一個(gè)近幾年非常熱門的第三方j(luò)ava庫(kù)桐磁,它以它強(qiáng)大的功能和出色的性能表現(xiàn)而廣為人知。那么,究竟為何FastJson能做到如此fast呢尉姨?它有什么秘訣?或者說(shuō)吗冤,它做了哪些優(yōu)化工作使得性能提升如此之多又厉?本文從作者的理解出發(fā)九府,結(jié)合代碼詳細(xì)分析FastJson的性能優(yōu)化方法和優(yōu)秀的編程實(shí)踐。
FastJson簡(jiǎn)介
首先來(lái)看看什么是FastJson覆致。
引用自github [https://github.com/alibaba/fastjson]:
Fastjson is a Java library that can be used to? convert Java Objects into their JSON representation. It can also be used to? convert a JSON string to an equivalent Java object. Fastjson can work with? arbitrary Java objects including pre-existing objects that you do not have? source-code of.
簡(jiǎn)單總結(jié)下就是:
1. Fastjson是一個(gè)java庫(kù)集合(server?side and android client)侄旬;
2. Fastjson可以將java對(duì)象和JSON字符串來(lái)回轉(zhuǎn)換;
? ? Ps. JSON(JavaScript?Object Notation, JavaScript對(duì)象表示法)是一種輕量級(jí)的數(shù)據(jù)交換格式煌妈。
3. Fastjson可以操作任何java對(duì)象儡羔,即使是一些預(yù)先存在的沒有源碼的對(duì)象。
Fastjson用途
Fastjson可以將java對(duì)象和JSON字符串來(lái)回轉(zhuǎn)換璧诵,所以它能被用作:
1. 對(duì)象的序列化后存儲(chǔ)(memcache, redis等)汰蜘、傳輸(web,?socket);
2. 接收數(shù)據(jù)后對(duì)象的還原即反序列化之宿。
Fastjson的牛掰之處
幾個(gè)主流json轉(zhuǎn)換工具的功能性能對(duì)比(摘自網(wǎng)絡(luò)):
幾個(gè)常用序列化工具的處理速度對(duì)比(摘自網(wǎng)絡(luò)):
從上面兩個(gè)表的對(duì)比數(shù)據(jù)來(lái)看鉴扫,
1.fastjson性能表現(xiàn)最好,解析速度最快澈缺,而且功能已經(jīng)足夠強(qiáng)大坪创,推薦使用;
2.轉(zhuǎn)換對(duì)象極其復(fù)雜情況下姐赡,可以考慮使用gson莱预。
Fastjson提供什么功能/特性
以下幾點(diǎn)摘自github [https://github.com/alibaba/fastjson]
1. Provide best performance in serverside and android client.
? ? 提供服務(wù)器端、安卓客戶端兩種解析工具项滑,性能表現(xiàn)業(yè)界最佳依沮。
2. Provide simple toJSONString() andparseObject() methods to convert Java objects to JSON and vice-versa
? ? 簡(jiǎn)單易用,調(diào)用toJSONString方法即可將對(duì)象轉(zhuǎn)換成json字符串枪狂,parseObject方法則反過(guò)來(lái)將json字符串轉(zhuǎn)換成對(duì)象危喉。
3. Allow pre-existing unmodifiableobjects to be converted to and from JSON
? ? 允許轉(zhuǎn)換預(yù)先存在的無(wú)法修改的對(duì)象(只有class、無(wú)源代碼)州疾。
4. Extensive support of Java Generics
? ? Java泛型的廣泛支持辜限。
5. Allow custom representations forobjects
? ? 允許對(duì)象的自定義表示、允許自定義序列化類严蓖。
6. Support arbitrarily complexobjects (with deep inheritance hierarchies and extensive use of generic types)
? ? 支持任意復(fù)雜對(duì)象(具有深厚的繼承層次和廣泛使用的泛型類型)薄嫡。
Fastjson的性能優(yōu)化
那么接下來(lái),我們分析下為什么Fastjson能做到這么快颗胡。分序列化和反序列化兩個(gè)過(guò)程分析毫深。
序列化
1. IdentityHashMap緩存各種序列化處理類,包括各種基本對(duì)象毒姨、集合對(duì)象哑蔫、第三方對(duì)象、自定義對(duì)象,方便序列化處理類的快速查找闸迷、避免JavaBeanSerializer的反復(fù)創(chuàng)建嵌纲。
更加詳細(xì)代碼請(qǐng)參考:https://github.com/alibaba/fastjson/blob/master/src/main/java/com/alibaba/fastjson/serializer/SerializeConfig.java
2. 使用ThreadLocal來(lái)存儲(chǔ)序列化過(guò)程中不斷append的字符串,減少內(nèi)存分配和gc稿黍,從而提高性能疹瘦。
3. 用類StringBuilder方式進(jìn)行字符串操作,配合ThreadLocal實(shí)現(xiàn)線程安全的StringBuilder巡球。
更加詳細(xì)代碼請(qǐng)參考:https://github.com/alibaba/fastjson/blob/master/src/main/java/com/alibaba/fastjson/serializer/SerializeWriter.java
4. 缺省啟用sort field輸出言沐,為deserialize優(yōu)化做準(zhǔn)備。
具體為什么開啟了排序的輸出能夠提升對(duì)象還原(反序列化)的效率酣栈,請(qǐng)查閱下面反序列化的“快速匹配”险胰。
5. 使用asm高效反射,fastjson-asm基于objectweb asm?3.3.1改造矿筝,只保留必要的部分起便,不到2000行代碼。具體代碼可參考:https://github.com/alibaba/fastjson/tree/master/src/main/java/com/alibaba/fastjson/asm
反序列化
1. IdentityHashMap緩存各種反序列化處理類窖维,包括基本對(duì)象榆综、集合對(duì)象、第三方對(duì)象铸史、自定義對(duì)象鼻疮,方便反序列化類的快速查找、避免JavaBeanDeserializer的反復(fù)創(chuàng)建琳轿。代碼與序列化的處理類緩存相似判沟,具體請(qǐng)參考:https://github.com/alibaba/fastjson/blob/master/src/main/java/com/alibaba/fastjson/parser/ParserConfig.java
2. 讀取token基于預(yù)測(cè)。在反序列化一個(gè)json字符串時(shí)崭篡,下一個(gè)字符一般情況下是可以預(yù)估的挪哄。比如字符}之后最有可能出現(xiàn)的是“,”、“]”琉闪、“}”或者結(jié)束符迹炼,有計(jì)劃、有預(yù)測(cè)地判斷token將能提升不少性能塘偎。于是Fastjson在實(shí)現(xiàn)的時(shí)候?qū)懥诉@樣一個(gè)函數(shù):
更加詳細(xì)的代碼請(qǐng)參考:https://github.com/alibaba/fastjson/blob/master/src/main/java/com/alibaba/fastjson/parser/JSONLexerBase.java
3. 快速匹配疗涉。在Fastjson反序列化過(guò)程中,有一個(gè)非常有用的效率改進(jìn)方法是有序json的快速匹配吟秩。所謂有序json就是json字符串中的key是按照字符排序好了的。上面已經(jīng)說(shuō)過(guò)绽淘,F(xiàn)astjson的序列化默認(rèn)是按照key的順序進(jìn)行的涵防,因此做反序列化時(shí)候,F(xiàn)astjson采用一種優(yōu)化算法,就是假設(shè)key/value的內(nèi)容是有序的壮池,讀取的時(shí)候只需要做key的匹配偏瓤,而不需要把key從輸入中讀取出來(lái)。通過(guò)這個(gè)優(yōu)化椰憋,使得Fastjson在處理json文本的時(shí)候厅克,少讀取超過(guò)50%的token,這個(gè)是一個(gè)十分關(guān)鍵的優(yōu)化算法橙依≈ぶ郏基于這個(gè)算法,使用asm實(shí)現(xiàn)窗骑,性能提升十分明顯女责,超過(guò)300%的性能提升。例:
{"id":123,"name":"testJson","salary":11}
在上面例子看创译,虛線標(biāo)注的三個(gè)部分是key抵知,如果key_id、key_name软族、key_salary這三個(gè)key是順序的刷喜,就可以做優(yōu)化處理,這三個(gè)key不需要被讀取出來(lái)立砸,只需要比較就可以了掖疮。
這種算法分兩種模式,一種是快速模式仰禽,一種是常規(guī)模式氮墨。快速模式是假定key是順序的吐葵,能快速處理规揪,如果發(fā)現(xiàn)不能夠快速處理,則退回常規(guī)模式温峭。保證性能的同時(shí)猛铅,不會(huì)影響功能。在這個(gè)例子中凤藏,常規(guī)模式需要處理13個(gè)token奸忽,快速模式只需要處理6個(gè)token。實(shí)現(xiàn)代碼片段如下:
詳細(xì)代碼請(qǐng)參考:https://github.com/alibaba/fastjson/blob/master/src/main/java/com/alibaba/fastjson/parser/deserializer/JavaBeanDeserializer.java
4. 使用asm高效反射
同上序列化的asm反射揖庄。
5. symbolTable算法緩存關(guān)鍵字栗菜,避免創(chuàng)建新的字符串對(duì)象。試想一下蹄梢,假設(shè)一個(gè)json字符串中疙筹,有成千上萬(wàn)個(gè)同樣的json對(duì)象的數(shù)組,那么在轉(zhuǎn)換過(guò)程中,如果不對(duì)這些json對(duì)象中的key做緩存而咆,將會(huì)存在成千上萬(wàn)個(gè)同樣的字符串對(duì)象(值相同)霍比,顯然這樣會(huì)浪費(fèi)極大的內(nèi)存和性能。于是Fastjson寫了一個(gè)SymbolTable類來(lái)緩存這些臨時(shí)字符串符號(hào)變量暴备。
更加詳細(xì)的代碼請(qǐng)參考:https://github.com/alibaba/fastjson/blob/master/src/main/java/com/alibaba/fastjson/parser/SymbolTable.java
最后
除了性能優(yōu)化之外悠瞬,F(xiàn)astjson還有許多編程思想和實(shí)踐是值得我們?nèi)W(xué)習(xí)的,只要用心去研究和挖掘涯捻,必定能學(xué)到很多能夠?qū)W以致用東西浅妆。當(dāng)然,也只有認(rèn)真去學(xué)習(xí)了并嘗試在平時(shí)項(xiàng)目開發(fā)過(guò)程中運(yùn)用汰瘫,才能夠真正提升自己的代碼水平狂打。后期有機(jī)會(huì)再給大家分享下Fastjson在ASM高效反射和泛型支持上的獨(dú)具匠心之處,請(qǐng)大家拭目以待混弥。J