Skip to content

Hprose 序列化

小马哥 edited this page Jun 22, 2016 · 29 revisions

概述

Hprose 提供了一套自己的序列化格式用来实现高效的跨语言跨平台的数据存储和交换。该序列化格式,在 hprose for Java 中被实现为以下几个对象:

  • HproseTags
  • HproseMode
  • HproseClassManager
  • HproseWriter
  • HproseReader
  • HproseFormatter

HproseTags 对象中包含了所有的 Hprose 序列化和 RPC 标记定义。Hprose 的使用者通常不需要关心该对象,因此这里不对该对象做详细介绍。

HproseMode 是一个枚举类型,表示序列化模式。其中包含了三个值:

  • FieldMode
  • PropertyMode
  • MemberMode

FieldMode 模式下只序列化 Java 类中的字段,包括私有字段,但是静态字段和 transient 字段不会序列化。

PropertyMode 模式下只序列化 Java 类中的 public 可读写属性。

MemberMode 模式下序列化 Java 类中的 public 可读写属性和字段,但不包括静态字段和 transient 字段。

HproseClassManager 用于管理自定义类型与其它语言之间的映射关系。

HproseWriter 用于进行细粒度的 Hprose 序列化操作。

HproseReader 用于进行细粒度的 Hprose 反序列化操作。

HproseFormatter 用于进行粗粒度的 Hprose 序列化和反序列化操作。

这些类都包含在 hprose.io 包中。下面我们将对这几个类进行详细的介绍。

HproseClassManager

register 方法

HproseClassManager.register(class, alias);

当 Hprose 序列化对象时,需要知道对象的类名,但有时候,我们在不同的语言中定义的类名可能不同,但结构相同或相近,我们希望这些定义不同的类的对象可以相互传递。那么就需要使用该方法来进行注册,注册成统一的别名之后,就可以相互传递了。

其中 class 表示要注册的类,alias 表示注册的别名。例如:

package hprose.example.io;

public class User {
    public String name;
    public int age;
}
...
HproseClassManager.register(User.class, "User");

在很多语言中,类名是有名称空间(NameSpace)的,例如上面的代码中,就是这样一个类:hprose.example.io.User,但也有写没有名称空间的概念,或者名称空间和类之间的分隔符不是用 .,而是用 : 或者 \ 等符号。比如假设我们在 PHP 中定义了一个 My\Model\User 类,但是并没有执行这个注册,我们又希望能够跟它交互,我们可以这样注册:

HproseClassManager.register(User.class, "My_Model_User");

注意上面的别名中,不是使用 . 做分隔符的,而是使用 _,Hprose 会自动将 _ 转换为对应语言的分隔符,对于不支持名称空间的语言,则直接对应 My_Model_User 这个名字,这样既可以支持没有名称空间的语言,也可以支持具有名称空间的语言。

getClassAlias 方法

HproseClassManager.getClassAlias(class);

通过类来查找别名,

getClass 方法

HproseClassManager.getClass(alias);

通过别名来查找注册的类。

containsClass 方法

HproseClassManager.containsClass(alias);

返回别名是否已注册,已注册返回 true,否则返回 false

下面来举一个完整的例子,来看一下上面几个方法是如何工作的:

package hprose.example.io;

import hprose.io.HproseClassManager;

public class ClassManagerExam {
    public static void main(String[] args) {
        HproseClassManager.register(User.class, "my_package_User");
        System.out.println(HproseClassManager.getClassAlias(User.class));
        System.out.println(HproseClassManager.getClass("my_package_User"));
        System.out.println(HproseClassManager.getClass("User"));
        System.out.println(HproseClassManager.containsClass("my_package_User"));
        System.out.println(HproseClassManager.containsClass("User"));
    }
}

输出结果为:

my_package_User
class hprose.example.io.User
null
true
false

HproseWriter

构造器

public HproseWriter(OutputStream stream);
public HproseWriter(OutputStream stream, boolean simple);
public HproseWriter(OutputStream stream, HproseMode mode);
public HproseWriter(OutputStream stream, HproseMode mode, boolean simple);

stream 参数是一个 OutputStream 的实例对象,序列化数据将会写入到该对象中。

mode 参数表示序列化对象的方式,三种方式在上面介绍 HproseMode 时大致上已经介绍过了。待后面介绍序列化对象时,再举例说明。

simple 参数如果为 true,则不使用引用方式序列化,通常在序列化的数据中不包含引用类型数据时,设置为 true 可以加快速度。当包含引用类型数据时,需要设置为 false(即默认值),尤其是当引用数据中包括递归数据时,如果不使用引用方式,会陷入死循环导致堆栈溢出的错误。

stream 字段

只读字段,返回当前用于写入序列化数据的 OutputStream 实例对象。该字段的值即上面构造器中的第一个参数。

serialize 方法

public final void serialize(Object obj) throws IOException;

该方法是 HproseWriter 的核心方法,功能是将任意对象序列化到 HproseWriter 所写入的流中。这里来举几个例子:

package hprose.example.io;

import hprose.io.ByteBufferStream;
import hprose.io.HproseClassManager;
import hprose.io.HproseWriter;
import hprose.util.StrUtil;
import java.io.IOException;

public class WriterSerializeExam {
    public static void main(String[] args) throws IOException {
        HproseClassManager.register(User.class, "my_package_User");
        ByteBufferStream stream = new ByteBufferStream();
        HproseWriter writer = new HproseWriter(stream.getOutputStream());
        writer.serialize(0);
        writer.serialize(1);
        writer.serialize(2);
        writer.serialize(3);
        writer.serialize(123);
        writer.serialize(3.14);
        writer.serialize("hello");
        writer.serialize("你好🇨🇳");
        writer.serialize(new char[] {'x', 'y', 'z'});
        writer.serialize(new Object[] {"x", "y", "z"});
        System.out.println(StrUtil.toString(stream));
        stream.rewind();
        User user = new User();
        user.name = "Tom";
        user.age = 18;
        writer.serialize(user);
        System.out.println(StrUtil.toString(stream));
    }
}

输出结果如下:

0123i123;d3.14;s5"hello"s6"你好🇨🇳"s3"xyz"a3{uxuyuz}
c15"my_package_User"2{s4"name"s3"age"}o0{s3"Tom"i18;}
Clone this wiki locally