java 序列化的幾種方式

什麼是序列化?

內存中的數據對象只有轉換爲二進制流纔可以進行數據持久化和網絡傳輸。將數據對象轉換爲二進制流的過程稱爲對象的序列化(Serialization)。反之,將二進制流恢復爲數據對象的過程稱爲反序列化(Deserialization)。序列化需要保留充分的信息以恢復數據對象,但是爲了節約存儲空間和網絡帶寬,序列化後的二進制流又要儘可能小。序列化常見的使用場景是RPC框架的數據傳輸。常見的序列化方式有三種:

備註:個人理解RPC框架(以二進制方式傳輸數據的調用)

 

1.Java原生序列化

Java類通過實現Serializable接口來實現該類對象的序列化,這個接口非常特殊,沒有任何方法,只起標識作用.Java序列化保留了對象類的元數據(如類、成員變量、繼承類信息等),以及對象數據等,兼容性最好,但不支持跨語言,而且性能一般。

實現Serializable接口的類建議設置serialVersionUID字段值,如果不設置,那麼每次運行時,編譯器會根據類的內部實現,包括類名、接口名、方法和屬性等來自動生成serialVersionUID。如果類的源代碼有修改,那麼重新編譯後serial VersionUID的取值可能會發生變化。因此實現Serializable接口的類一定要顯式地定義serialVersionUID屬性值。修改類時需要根據兼容性決定是否修改serialVersionUID值:
1.如果是兼容升級,請不要修改serialVersionUID字段,避免反序列化失敗。

2.如果是不兼容升級,需要修改serialVersionUID值,避免反序列化混亂。

使用Java原生序列化需注意,Java反序列化時不會調用類的無參構造方法,而是調用native方法將成員變量賦值爲對應類型的初始值。基於性能及兼容性考慮,不推薦使用Java 原生序列化。

2.Hessian 序列化

Hessian 序列化是一種支持動態類型、跨語言、基於對象傳輸的網絡協議。

Java 對象序列化的二進制流可以被其他語言 ( 如 C++、 Python )反序列化。 Hessian 協議具有如下特性.

自描述序列化類型。不依賴外部描述文件或接口定義 , 用一個字節表示常用基礎類型 , 極大縮短二進制流。
· 語言無關,支持腳本語言。
· 協議簡單,比 Java 原生序列化高效。
相比 Hessian 1.0, Hessian 2.0 中增加了壓縮編碼,其序列化二進制流大小是 Java序列化的 50% , 序列化耗時是 Java 序列的 30% ,反序列化耗時是 Java 反序列化的20% 。
Hessian 會把複雜對象所有屬性存儲在一個 Map 申 進行序列化。所以在父類、子類存在同名成員變量的情況下, Hessian 序列化時,先序列化子類 ,然後序列化父類,因此反序列化結果會導致子類同名成員變量被父類的值覆蓋。

3.Json序列化

JSON ( JavaScript O同ect Notation )是一種輕量級的數據交換格式。 JSON 序列化就是將數據對象轉換爲 JSON 字符串。在序列化過程中拋棄了類型信息,所以反序列化時只有提供類型信息才能準確地反序列化。相比前兩種方式,JSON 可讀性比較好,方便調試。序列化通常會通過網絡傳輸對象 , 而對象中往往有敏感數據,所以序列化常常成爲黑客的攻擊點,攻擊者巧妙地利用反序列化過程構造惡意代碼,使得程序在反序列化的過程中執行任意代碼。 Java 工程中廣泛使用的 Apache Commons Collections 、Jackson 、 fastjson 等都出現過反序列化漏洞。如何防範這種黑客攻擊呢?有些對象的敏感屬性不需要進行序列化傳輸 ,可以加 transient 關鍵字,避免把此屬性信息轉化爲序列化的二進制流。如果一定要傳遞對象的敏感屬性,可以使用對稱與非對稱加密方式獨立傳輸,再使用某個方法把屬性還原到對象中。應用開發者對序列化要有一定的安全防範意識 , 對傳入數據的內容進行校驗或權限控制,及時更新安全漏洞,避免受到攻擊。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章