hessian序列化原理分析

1. hessian序列化舉例

1.1 hessian協議簡介

1.1.1 特點

參考官方文檔的描述,下面做一些簡要描述,http://hessian.caucho.com/doc/hessian-serialization.html。

  • 它必須自我描述序列化類型,即不需要外部模式或接口定義
  • 它必須是獨立於語言的,包括支持腳本語言
  • 它必須是可以通過單一方式進行讀寫
  • 它必須儘可能緊湊
  • 它必須簡單,這樣纔能有效地測試和實現
  • 必須儘可能地快
  • 它必須支持Unicode字符串
  • 它必須支持8位二進制數據,而不需要轉義或使用附件
  • 它必須支持加密、壓縮、簽名和事務上下文信封
1.1.2 hessian語法簡介

以下幾種示例,更多參考:http://hessian.caucho.com/doc/hessian-serialization.html。

        #boolean true/false
boolean ::= 'T'
        ::= 'F'
          
        # list/vector
list    ::= 'V' type? length? value* 'z'
        ::= 'v' int int value*          #第一個int表示類型引用, 第二個int表示長度
          

        #32-bit 有符號整型(比如0x90編碼爲0int     ::= 'I' b3 b2 b1 b0
        ::= [x80-xbf]                   #-x10 to x3f
        ::= [xc0-xcf] b0                #-x800 to x7ff
        ::= [xd0-xd7] b1 b0             #-x40000 to x3ffff

1.2 hessian序列化與反序列化舉例

public static void serialize1(Student student){
  FileOutputStream fileOutputStream;
  try {
    fileOutputStream = new FileOutputStream("/Users/zhuqiuhui/Desktop/studentHession.txt");
    // 從對象中獲取字節流
    ByteArrayOutputStream os = new ByteArrayOutputStream();
    Hessian2Output output = new Hessian2Output(os);
    output.writeObject(student);
    output.getBytesOutputStream().flush();
    output.completeMessage();
    output.close();

    // 寫入到文件中
    fileOutputStream.write(os.toByteArray());
  } catch (Exception e) {
    e.printStackTrace();
  }
}

public static Student deserialize1(){
  FileInputStream fileInputStream;
  Object result = null;
  try {
    fileInputStream = new FileInputStream("/Users/zhuqiuhui/Desktop/studentHession.txt");
    byte[] data = new byte[1024];
    int len = fileInputStream.read(data);
    System.out.println("read byte length:" + len);

    // 從流中讀出對象
    ByteArrayInputStream is = new ByteArrayInputStream(data);
    Hessian2Input input = new Hessian2Input(is);
    result = input.readObject();
  } catch (Exception e) {
    e.printStackTrace();
  }
  return (Student)result;
}

public static void main(String[] args) {

  Student student = new Student();
  student.setId("123");
  student.setName("方辰");

  // 序列化
  // serialize1(student);

  // 反序列化
  Student serializestudent = deserialize1();
  System.out.println("deserialize result entity id is "+serializestudent.getId());
  System.out.println("deserialize result entity name is "+serializestudent.getName());
}

1.3 hessian協議與jdk區別

  • 區別一:java序列化無法跨語言
  • 區別二:新舊對象的版本Java通過一個serialVersionUID來關聯,需要開發者關注序列化的語義
  • 區別三:java序列化不支持加密
  • 區別四:Java序列化的內容比hessian大

2. hessian序列化分析

2.1 hessian序列化必須 serialVersionUID 嗎?

hessian序列化對象不用增加serialVersionUID,hessian序列化時把類的描述信息寫入到byte[]中

2.2 hessian序列化與反序列化源碼分析

2.2.1 (反)序列化器的對應關係
類型 序列化器 反序列化器
Collection CollectionSerializer CollectionDeserializer
Map MapSerializer MapDeserializer
Iterator IteratorSerializer IteratorDeserializer
Annotation AnnotationSerializer AnnotationDeserializer
Interface ObjectSerializer ObjectDeserializer
Array ArraySerializer ArrayDeserializer
Enumeration EnumerationSerializer EnumerationDeserializer
Enum EnumSerializer EnumDeserializer
Class ClassSerializer ClassDeserializer
默認 JavaSerializer JavaDeserializer
Throwable ThrowableSerializer
InputStream InputStreamSerializer InputStreamDeserializer
InetAddress InetAddressSerializer
2.2.2 爲什麼序列化對象要 implements Serializable 接口?
// com.caucho.hessian.io.SerializerFactory 序列化時會獲取默認序列化器
protected Serializer getDefaultSerializer(Class cl) {
  if (_defaultSerializer != null)
    return _defaultSerializer;

  // 若序列化對象沒有實現 Serializable 接口,則會拋出IllegalStateException
  if (! Serializable.class.isAssignableFrom(cl)
      && ! _isAllowNonSerializable) {
    throw new IllegalStateException("Serialized class " + cl.getName() + " must implement java.io.Serializable");
  }

  if (_isEnableUnsafeSerializer
      && JavaSerializer.getWriteReplace(cl) == null) {
    return UnsafeSerializer.create(cl);
  }
  else
    return JavaSerializer.create(cl);
}
2.2.3 序列化過程與反序列化過程
  • 序列化過程:Hessian2Output -> SerializerFactory -> Serializer
  • 反序列化過程:Hessian2Input -> SerializerFactory -> Deserializer

2.3 總結

  • 序列化對象要實現 Serializable 接口,否則序列化時會報“must implement java.io.Serializable”異常
  • 若序列化對象經hessian序列化後,序列化對象中不加serialVersionUID時,再改變(增加對象屬性、刪除對象屬性)都不會產生反序列化異常,即hessian序列化對象不再需要serialVersionUID
  • hessian會把複雜對象所有屬性存儲在一個 Map 中進行序列化。所以在父類、子類存在同名成員變量的情況下, Hessian 序列化時,先序列化子類,然後序列化父類,因此反序列化結果會導致子類同名成員變量被父類的值覆蓋。
  • hessian中的writeReplace方法與readResolve方法的作用一樣,如果序列化的對象具有此方法,會利用此方法返回的實例來代替序列化後實例,用以保證對象的單例性
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章