- 背景
最近在處理一個hessian的反序列化問題時,因爲服務端使用了pojo bean中多了一個enum屬性,導致客戶端在反序列化時瘋狂的在打印日誌。警告說找不到對應的enum class,因爲項目中本身是設置了log4j的根輸出爲一個文件。
比較奇怪的是,hessian對應的日誌輸出全都打印到了控制檯(雖然我們對console進行了重定向輸出),導致對應的文件達到幾百MB。無奈之下,仔細分析了下hessian的源碼。
介紹
先看一張hessian主要的幾個概念圖
說明:
- Serializer 序列化的接口
- Deserializer 反序列化的接口
- AbstractHessianInput hessian自定義的輸入流,提供對應的read各種類型的方法
- AbstractHessianOutput hessian自定義的輸出流,提供對應的write各種類型的方法
AbstractSerializerFactory介紹
serializerFactory從字面意思上也看的出來,是管理和維護對應序列化/反序列化機制的工廠。默認的幾種實現
- SerializerFactory 標準的實現
- ExtSerializerFactory 我們可以設置自定義的序列化機制,通過該Factory可以進行擴展。
- BeanSerializerFactory 對SerializerFactory的默認object的序列化機制進行強制指定,指定爲BeanSerializer。 具體BeanSerializer的實現後面再表。
自定義序列化機制的擴展:
- 實現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] 進行舉報,並提供相關證據,一經查實,本社區將立刻刪除涉嫌侵權內容。