
記憶體中的資料對象隻有轉換成二進制才可以進行資料持久化和網絡傳輸。将資料對象轉換成二進制的流程稱之為對象的序列化(Serialization)。
反之,将二進制流恢複為資料對象的過程稱之為反序列化(Deserialization)。序列化需要保留充分的資訊以恢複資料對象,但是為了節省存儲空間和網絡帶寬,序列化後的二進制流又要盡可能的小。序列化常見的使用時RPC架構的資料傳輸。
Java類型通過實作Serializable接口來實作該類對象的序列化,這個接口非常特殊,沒有任何方法,隻是起到一個辨別符的作用。Java序列化保留了對象的中繼資料(如類、成員變量、繼承類資訊等),以及對象資料等,相容性最好,但是不支援跨語言,同時性能不是最好的。
實作Serializable接口的類建議設定serialVersionUID字段值,如果不設定,那麼每次運作時,編譯器會根據類的内部實作,包括類名、接口名、方法名和屬性等來自動生成serialVersionUID。如果類的源代碼有修改,那麼重新編譯後serialVersionUID的取值可能會變化。是以實作Serializable接口的類最好是顯示低設定serialVersionUID值,修改類時候可以根據需要或者相容性來決定是否需要修改serialVersionUID值。
SerialVersionUID是一個辨別符,當它通常使用對象的哈希碼序列化時會标記在對象上。我們可以通過Java中serialver工具找到該對象的serialVersionUID。
如果是相容更新,請不要修改serialVersionUID字段,避免反序列化失敗 java.io.NotSerializableException。
如果是不相容更新,需要修改serialVersionUID值,避免反序列化失敗java.io.NotSerializableException。
使用Java原生态序列化需要注意,Java反序列化時候不會調用類的無參構造方法,而是調用native方法将成員變量指派為對應類型的初始值,基于性能以及相容性的考慮,不推薦使用Java序列化。
Hessian序列化是一種支援動态類型、跨語言、基于對象傳輸的網絡協定。Java對象序列化的二進制流可以被其他語言(如:C++,python等語言)反序列化。
特性:
自描述序列化類型,不依賴外部描述檔案或接口定義,用一個位元組表示常用基礎類型,極大的縮短了二進制流。
語言無關性,支援腳本語言
協定簡單,比Java原生态序列化高效
相比Hessian 1.0、Hessian 2.0中增加了壓縮編碼,其序列化二進制流大小是Java原生态序列化的50%,序列化耗時是Java原生态大小的30%,反序列化耗時是Java原生态反序列化的20%。
Hessian 會把複雜對象所有屬性存儲在一個map中進行序列化。是以在父類、子類存在同名成員變量的情況下,Hessian 序列化時,先序列化子類,然後序列化父類,是以反序列化結果會導緻子類同名成員變量被父類的值覆寫。
JSON序列化這裡的JSON=JavaScript Object Notation,是一種輕量級的資料交換格式,JSON 序列化就是将資料對象轉換成JSON字元串。在序列化過程中跑起來類型資訊,是以反序列化時候隻有提供類型資訊才能準确低反序列化。相比前面兩種方式JSON可讀性筆記好,友善調試。
序列化通常會通過網絡協定傳輸對象,而對象中往往有敏感資料,是以序列化常常是黑客們的攻擊點,攻擊者窮秒地利用反序列化過程構造惡意代碼,是得程式在反序列化過程中執行任意代碼。
Java工程中廣泛使用的Apache Commons Collections、Jackson、fastjson等都出現過反序列化漏洞。
将一些對象的敏感資訊不進行序列化傳輸,可以加關鍵字transient修飾,避免把該屬性資訊轉化為序列化的二進制流。如果一定要傳遞對象的敏感資訊,也可以使用對稱加密和非對稱加密方式獨立傳輸,再使用某個方法把屬性還原丹對象中。transient 修飾符僅适用于變量,不适用于方法和類。在序列化時,如果我們不想序列化特定變量以滿足安全限制,那麼我們應該将該變量聲明為transient。執行序列化時,JVM會忽略transient變量的原始值并将預設值儲存到檔案中。是以,transient意味着不要序列化。
應用開發者對序列化要有一定的安全意識防範,對傳入資料的内容進行校驗或者權限控制,及時更新安全漏洞,避免遭到黑客攻擊。
目前對于Java開源的JSON類庫有很多種,下面我們取4個常用的JSON庫進行性能測試對比, 同時根據測試結果分析如果根據實際應用場景選擇最合适的JSON庫。
這4個JSON類庫分别為:Gson,FastJson,Jackson,Json-lib。
簡單介紹
選擇一個合适的JSON庫要從多個方面進行考慮:
字元串解析成JSON性能
字元串解析成JavaBean性能
JavaBean構造JSON性能
集合構造JSON性能
易用性
先簡單介紹下四個類庫的身份背景
Gson
項目位址:https://github.com/google/gson
Gson是目前功能最全的Json解析神器,Gson當初是為因應Google公司内部需求而由Google自行研發而來,但自從在2008年五月公開釋出第一版後已被許多公司或使用者應用。Gson的應用主要為toJson與fromJson兩個轉換函數,無依賴,不需要例外額外的jar,能夠直接跑在JDK上。在使用這種對象轉換之前,需先建立好對象的類型以及其成員才能成功的将JSON字元串成功轉換成相對應的對象。類裡面隻要有get和set方法,Gson完全可以實作複雜類型的json到bean或bean到json的轉換,是JSON解析的神器。
FastJson
項目位址:https://github.com/alibaba/fastjson
Fastjson是一個Java語言編寫的高性能的JSON處理器,由阿裡巴巴公司開發。無依賴,不需要例外額外的jar,能夠直接跑在JDK上。FastJson在複雜類型的Bean轉換Json上會出現一些問題,可能會出現引用的類型,導緻Json轉換出錯,需要制定引用。FastJson采用獨創的算法,将parse的速度提升到極緻,超過所有json庫。
Jackson
項目位址:https://github.com/FasterXML/jackson
Jackson是目前用的比較廣泛的,用來序列化和反序列化json的Java開源架構。Jackson社群相對比較活躍,更新速度也比較快, 從Github中的統計來看,Jackson是最流行的json解析器之一,Spring MVC的預設json解析器便是Jackson。
Jackson優點很多:
Jackson 所依賴的jar包較少,簡單易用。
與其他 Java 的 json 的架構 Gson 等相比,Jackson 解析大的 json 檔案速度比較快。
Jackson 運作時占用記憶體比較低,性能比較好
Jackson 有靈活的 API,可以很容易進行擴充和定制。
目前最新版本是2.9.4,Jackson 的核心子產品由三部分組成:
jackson-core 核心包,提供基于”流模式”解析的相關 API,它包括 JsonPaser 和 JsonGenerator。Jackson 内部實作正是通過高性能的流模式 API 的 JsonGenerator 和 JsonParser 來生成和解析 json。
jackson-annotations 注解包,提供标準注解功能;
jackson-databind 資料綁定包,提供基于”對象綁定” 解析的相關 API( ObjectMapper )和”樹模型” 解析的相關 API(JsonNode);基于”對象綁定” 解析的 API 和”樹模型”解析的 API 依賴基于”流模式”解析的 API。
Json-lib
項目位址:http://json-lib.sourceforge.net/index.html
json-lib最開始的也是應用最廣泛的json解析工具,json-lib 不好的地方确實是依賴于很多第三方包,對于複雜類型的轉換,json-lib對于json轉換成bean還有缺陷, 比如一個類裡面會出現另一個類的list或者map集合,json-lib從json到bean的轉換就會出現問題。json-lib在功能和性能上面都不能滿足現在網際網路化的需求。
編寫性能測試
接下來開始編寫這四個庫的性能測試代碼。
添加maven依賴
當然首先是添加四個庫的maven依賴,公平起見,我全部使用它們最新的版本:
四個庫的工具類
<code>FastJsonUtil.java</code>
GsonUtil.java
JacksonUtil.java
JsonLibUtil.java
準備Model類
這裡我寫一個簡單的Person類,同時屬性有Date、List、Map和自定義的類FullName,最大程度模拟真實場景。
JSON序列化性能基準測試
說明一下,上面的代碼中
ResultExporter.exportResult("JSON序列化性能", results, "count", "秒");
這個是我自己編寫的将性能測試報告資料填充至Echarts圖,然後導出png圖檔的方法,具體代碼我就不貼了,參考我的github源碼。
執行後的結果圖:
從上面的測試結果可以看出,序列化次數比較小的時候,Gson性能最好,當不斷增加的時候到了100000,Gson明細弱于Jackson和FastJson, 這時候FastJson性能是真的牛,另外還可以看到不管數量少還是多,Jackson一直表現優異。而那個Json-lib簡直就是來搞笑的。^_^
JSON反序列化性能基準測試
從上面的測試結果可以看出,反序列化的時候,Gson、Jackson和FastJson差別不大,性能都很優異,而那個Json-lib還是來繼續搞笑的。
| 來源:公衆号方志朋,公衆号Java後端技術棧