hession 源碼解析 自定義序列化器

  1. 背景

    最近在處理一個hessian的反序列化問題時,因爲服務端使用了pojo bean中多了一個enum屬性,導致客戶端在反序列化時瘋狂的在打印日誌。警告說找不到對應的enum class,因爲項目中本身是設置了log4j的根輸出爲一個文件。 

    比較奇怪的是,hessian對應的日誌輸出全都打印到了控制檯(雖然我們對console進行了重定向輸出),導致對應的文件達到幾百MB。無奈之下,仔細分析了下hessian的源碼。

介紹

 

先看一張hessian主要的幾個概念圖

說明:

 

  1. Serializer  序列化的接口
  2. Deserializer 反序列化的接口
  3. AbstractHessianInput  hessian自定義的輸入流,提供對應的read各種類型的方法
  4. AbstractHessianOutput  hessian自定義的輸出流,提供對應的write各種類型的方法

 

AbstractSerializerFactory介紹

serializerFactory從字面意思上也看的出來,是管理和維護對應序列化/反序列化機制的工廠。默認的幾種實現

 

  • SerializerFactory 標準的實現
  • ExtSerializerFactory 我們可以設置自定義的序列化機制,通過該Factory可以進行擴展。
  • BeanSerializerFactory 對SerializerFactory的默認object的序列化機制進行強制指定,指定爲BeanSerializer。 具體BeanSerializer的實現後面再表。

自定義序列化機制的擴展:

  1. 實現Serializer/Deserializer接口
1.ExtSerializerFactory extSerializerFactory = new ExtSerializerFactory();  
2.extSerializerFactory.addSerializer(class , mySerializer); //添加自定義的序列化接口  
3.extSerializerFactory.addDeserializer(class , myDeserializer); //添加自定義的反序列化接口  
4.  
5.serializerFactory.addFactory(extSerializerFactory); //註冊ext到序列化工廠  

 

SerializerFactory介紹:

先看一下hesian提供的Serializer/Derializer幾種默認實現

 



 


 

 

具體的實現就不細說,有興趣的自己看代碼去。

下面提一下我在看得過程中比較在意和疑惑過的點。

 

1.  Object對象的序列化/反序列化

答:JavaSerializer或者BeanSerializer。這兩者的區別

 

  • JavaSerializer是通過反射獲取所有bean的屬性進行序列化,排除static和transient屬性,對其他所有的屬性進行遞歸序列化處理(比如屬性本身是個對象)。
  • BeanSerializer是遵循pojo bean的約定,掃描bean的所有方法,發現存在get和set方法的屬性進行序列化,它並不直接直接操作所有的屬性,比較溫柔。 注意:BeanSerializer將會無法處理你的boolean屬性,因爲通過默認的eclipse生成的方法是以isXXX打頭,不會被序列化。

2.  枚舉對象的序列化/反序列化

答:看過類圖後,就很明顯的發現存在一個EnumSerializer和EnumDeserializer實現。大家都知道枚舉對象全都繼承於enum對象,所以EnumSerializer會反射調用name方法,EnumDeserializer是反射調用valueof方法。這樣就很明顯了,如果服務端多了一個枚舉值定義,客戶端反序列化會出現異常,不會是一個兼容的過程。

 

補充:測試過程中,hessian 3.1.3版本存在enum序列化問題,低級的問題。

 

3.  服務端拋異常後的序列化/反序列化

答:這個也是在做rpc調用,一個比較容易被遺忘的點,只關注了正常的業務功能的流程,卻沒有考慮對應的異常處理的序列化和反序列化。hessian提供了ThrowableSerializer和StackTraceElementDeserializer進行序列化處理。

  • ThrowableSerializer會按照object的序列化方式,傳遞對應的信息到客戶端。包括stackTrace和detailMessage等。
  • StackTraceElementDeserializer反序列化對應的異常棧信息。異常的其他屬性通過JavaSerializer進行反序列化處理。

補充:測試過程中,hessian 3.0.20,3.1.3版本存在問題,異常的反序列化在hessian 1.0協議是正常的,到2.0就會出現錯誤。 具體的問題也有人報告了bug : http://maillist.caucho.com/pipermail/hessian-interest/2008-February/000297.html ,升級到3.1.5之後就解決了.

 

測試代碼

1.public static void exceptionTest() throws Exception {  
2.    Exception exception = null;  
3.    try {  
4.        FileInputStream stream = new FileInputStream("notfound");  
5.    } catch (FileNotFoundException e) {  
6.        exception = e;  
7.    }  
8.  
9.    ByteArrayOutputStream bos = new ByteArrayOutputStream();  
10.    HessianOutput out = new HessianOutput(bos);  
11.    out.writeObject(exception);  
12.    out.flush();  
13.  
14.    byte[] bytes = bos.toByteArray();  
15.    ByteArrayInputStream bin = new ByteArrayInputStream(bytes);  
16.    HessianInput in = new HessianInput(bin);  
17.    Exception read = (Exception) in.readObject(FileNotFoundException.class);  
18.    read.printStackTrace();  
19.    System.out.println(read);  
20.}  


hessian支持對流進行壓縮處理,可以看下 Deflation

1.Hessian2Output out = new Hessian2Output(bos);  
2.out = envelope.wrap(out); //包裝爲壓縮  
3.  
4.Hessian2Input in = new Hessian2Input(bin);  
5.in = envelope.unwrap(in); //解縮

 

壓縮慎用,在測試過程中有一些磕磕碰碰的小問題。 

 

後記

hessian序列化機制的性能比較,後續補上。 主要是和原先的幾種序列化協議相關數據對比

 

 

序列化數據對比


bytes字節數對比


 

具體的數字: 

  protobuf jackson xstream Serializable hessian2 hessian2壓縮 hessian1
序列化(單位ns) 1154 5421  92406  10189 26794 100766 29027
反序列化(單位ns) 1334 8743  117329  64027 37871 188432 37596
bytes 97 311  664  824 374 283 495

 

版權聲明:本文內容由互聯網用戶自發貢獻,版權歸作者所有,本社區不擁有所有權,也不承擔相關法律責任。如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至:[email protected] 進行舉報,並提供相關證據,一經查實,本社區將立刻刪除涉嫌侵權內容。

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