Java序列化詳解

 

轉載請註明原文地址:http://www.javashuo.com/article/p-repxrjqs-mv.htmlhtml

 

一:什麼是序列化與反序列化

  序列化:對象序列化是指將Java對象(動態的狀態,如變量、函數)轉換爲字節流的過程,能夠將其保存到磁盤文件中或經過網絡發送到任何其餘程序。前端

  反序列化:從字節流重構出Java對象的過程。java

  序列化獲得的字節流是與平臺無關的,在一個平臺上序列化的對象能夠在不一樣的平臺上反序列化。python

 

二:序列化的做用

  1)對象持久化

  咱們知道,對象隨着程序的運行而被建立,而後在不可達時被回收,生命週期是短暫的。可是若是咱們想長久地把對象的內容保存起來怎麼辦呢?把它轉化爲字節序列保存在存儲介質上便可。那就須要序列化。算法

  2)網絡傳輸對象

  咱們知道,兩個進程之間通訊時,傳遞的音頻、視頻等信息是以二進制序列形式來傳輸的。那麼,對象也能夠嗎?能夠,經過序列化把主機A進程上的對象序列化爲二進制序列,傳輸到主機B上的進程從序列中重構出該對象。這在RMI中應用普遍,RMI的結果能夠是一個對象。數據庫

  3)進程間傳遞對象

  

 

三:如何序列化

  一、讓類對象能夠被序列化

  1)默認序列化方式json

  定義類時實現Serializable接口便可,這個Serializable接口是一個空接口,沒有須要實現的方法。安全

  做用是標記該類的對象能夠被序列化,啓用其序列化功能。經過調用 ObjectOutputStream和ObjectInputStream的方法來便可對該對象進行序列化和反序列化。服務器

 

  2)實現Serializable接口網絡

  定義類時,實現Serializable接口,並在類中重寫兩個序列化與反序列化接口,在其中定義對象序列化與反序列化動做。

private void writeObject(java.io.ObjectOutputStream out)
     throws IOException

private void readObject(java.io.ObjectInputStream in)
     throws IOException, ClassNotFoundException;
   

  這兩個方法,在方法中經過對象輸入流參數、對象輸出流參數進行自定義的內容輸出。

  這樣經過 ObjectOutputStream和ObjectInputStream 序列化和反序列化對象時會自動調用類中定義的writeObject、和readObject方法而不是默認的序列化和反序列化方法。

 

  3)實現Externalnalizable接口

  在類中實現readExternal(ObjectInput in)和writeExternal(ObjectOutput out)方法,在方法中定義類對象自定義的序列化和反序列化操做。

  這樣經過對象輸出流和對象輸入流的輸入輸出方法序列化和反序列化對象時會自動調用類中定義的readExternal(ObjectInput in)和writeExternal(ObjectOutput out)方法。

 

  二、序列化與反序列化API與使用過程

  1)定義一個類,實現Serializable接口或者Externalizable接口,實現相應的序列化和反序列化方法(也可採起默認方法);

  2)在程序代碼中建立對象後,建立對象輸出流ObjectOutputStream對象並在構造參數中指定流的輸出目標(好比一個文件),經過objectOutputStream.writeObject(obj)把對象序列化並輸出到流目標處;

  3)在須要提取對象處:建立對象輸入流ObjectInputStream對象並在構造參數中指定流的來源,而後經過readObject()方法獲取對象,並經過強制類型轉換賦值給類對象引用。

 

四:序列化底層原理

  序列化算法會按步驟執行如下事情:

  1)當前類描述的元數據輸出爲字節序列;【類定義描述、類中屬性定義描述】

  2)超類描述輸出爲字節序列;【若是超類還有超類,則依次遞歸,直至沒有超類】

  3)從最頂層超類往下,依次輸出各種屬性值描述,直至當前類對象屬性值。

  即:從下到上描述類定義,從上往下輸出屬性值。

 

五:序列化的特殊狀況 

  1)靜態變量和transient關鍵字修飾的變量不能被序列化;

  2)反序列化時要按照序列化的順序重構對象:如先序列化A後序列化B,則反序列化時也要先獲取A後獲取B,不然報錯。

  3)serialVersionUID(序列化ID)的做用:決定着是否可以成功反序列化。

  虛擬機是否容許對象反序列化,不是取決於該對象所屬類路徑和功能代碼是否與虛擬機加載的類一致,而是主要取決於對象所屬類與虛擬機加載的該類的序列化 ID 是否一致

  java的序列化機制是經過在運行時判斷類的serialVersionUID來驗證版本一致性的。在進行反序列化時,JVM會把傳來的字節流中的serialVersionUID與本地實體類中的serialVersionUID進行比較,若是相同則認爲是一致的,即可以進行反序列化,不然就會報序列化版本不一致的異常。

  4)自定義序列化方法的應用場景:對某些敏感數據進行加密操做後再序列化;反序列化對加密數據進行解密操做。

  5)重複序列化:同一個對象重複序列化時,不會把對象內容再次序列化,而是新增一個引用指向第一次序列化時的對象而已。

 

六:序列化破壞單例模式

  見另外一篇博文:http://www.javashuo.com/article/p-xfppzqug-dv.html

 

七:爲何說反序列化並不安全——序列化漏洞[反序列化攻擊]

   反序列化是一系列安全問題的根源:攻擊者可以將惡意數據序列化並存儲到數據庫或內存中,當應用進行反序列化時,應用會執行到惡意代碼。  

   在谷歌內部,這個缺陷被稱爲「瘋狂的小部件 (Mad Gadget)」,外界對它的叫法是 「Java 啓示錄 (Apocalypse)」。

 

  怎樣規避序列化漏洞:

  1)對序列化對象執行完整性檢查或加密,以防止惡意對象建立或數據篡改;最多見的例子之一就是JWT:JWT由3部分組成:Header,Payload,Verify Signature,最後的簽名部分其實就是對數據進行完整性校驗的關鍵部分,用secret對數據部分進行哈希計算,隨後檢查計算出來的哈希值是否和請求中的JWT簽名部分的哈希值相同。若二者一致則認爲數據完整性沒有被破壞,若二者有差別則說明數據被修改過。

  2)在建立對象以前強制執行嚴格的類型約束;

  3)隔離反序列化的代碼,使其在很是低的特權環境中運行;

  4)記錄反序列化的例外狀況和失敗信息,如:傳入的類型不是預期的類型,或者反序列處理引起的例外狀況;

  5)限制或監視來自於容器或服務器傳入和傳出的反序列化網絡鏈接;

  6)監視反序列化,當用戶持續進行反序列化時,對用戶進行警告。

 

八:protobuf


  protobuf:谷歌公司出的一款開源項目,序列號性能好,效率高,而且支持多種語言,例如:java,C++,python等。

  protobuf3語言語法:http://www.javashuo.com/article/p-zdwnwglv-hw.html

  protobuf3簡單使用:https://blog.csdn.net/fangxiaoji/article/details/78826165
  

九:其餘序列化方式對比

  目前JAVA經常使用的序列化有protobuf,json,xml,Serializable,hessian,kryo。

    • JSON:用途最普遍,序列化方式還衍生了阿里的fastjson,美團的MSON,谷歌的GSON等更加優秀的轉碼工具。
      優勢:使用方便。
      缺點:數據冗長,轉碼性能通常。

    • XML:好久以前的轉碼方法,如今用的很少。
      優勢:暫時沒發現。
      缺點:數據冗長,轉碼性能通常。

    • Serialzable:JDK自帶的序列化。
      優勢:使用方便。
      缺點:沒法跨語言、序列化的碼流太大  、轉碼性能低下、存在安全漏洞。

    • hessian:基於 binary-RPC實現的遠程通信library,使用二進制傳輸數據。
      優勢:數據長度小。
      缺點:性能低下。

    • kryo:快速、高效的序列化框架。只能在java中使用,和前端非java語言的通信存在極大的隔閡。
    • protobuf:谷歌公司出的一款開源項目,轉碼性能高,支持多語言。
相關文章
相關標籤/搜索