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方法的作用一样,如果序列化的对象具有此方法,会利用此方法返回的实例来代替序列化后实例,用以保证对象的单例性
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章