文章目錄
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編碼爲0)
int ::= '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方法的作用一樣,如果序列化的對象具有此方法,會利用此方法返回的實例來代替序列化後實例,用以保證對象的單例性。