一、序列化:对象怎么在网络中传输?

一.为什么需要序列化?

首先得知道什么是序列化与反序列化。

网络传输的数据必须是二进制数据,但调用方请求的出入参数都是对象。对象是不能直接在网络中传输的,所以我们需要提前把它转成可传输的二进制,并且要求转换算法是可逆的,这个过程我们一般叫做“序列化”。 这时,服务提供方就可以正确地从二进制数据中分割出不同的请求,同时根据请求类型和序列化类型,把二进制的消息体逆向还原成请求对象,这个过程我们称之为“反序列化”。

axios数字对象对象序列化后传参 对象序列化传输_反序列化


总结来说,序列化就是将对象转换成二进制数据的过程,而反序列就是反过来将二进制转换为对象的过程。

二.常用的序列化

1、JDK 原生序列化:实现Serializable

import java.io.*;

public class Student implements Serializable {
    //学号
    private int no;
    //姓名
    private String name;

    public int getNo() {
        return no;
    }

    public void setNo(int no) {
        this.no = no;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        return "Student{" +
                "no=" + no +
                ", name='" + name + '\'' +
                '}';
    }

    public static void main(String[] args) throws IOException, ClassNotFoundException {
        String home = System.getProperty("user.home");
        String basePath = home + "/Desktop";
        FileOutputStream fos = new FileOutputStream(basePath + "student.dat");
        Student student = new Student();
        student.setNo(100);
        student.setName("TEST_STUDENT");
        ObjectOutputStream oos = new ObjectOutputStream(fos);
        oos.writeObject(student);
        oos.flush();
        oos.close();

        FileInputStream fis = new FileInputStream(basePath + "student.dat");
        ObjectInputStream ois = new ObjectInputStream(fis);
        Student deStudent = (Student) ois.readObject();
        ois.close();

        System.out.println(deStudent);

    }
}

序列化具体的实现是由 ObjectOutputStream 完成的,而反序列化的具体实现是由 ObjectInputStream 完成的。

axios数字对象对象序列化后传参 对象序列化传输_序列化_02

2、JSON

JSON 是典型的 Key-Value 方式,没有数据类型,是一种文本型序列化框架.
用 JSON 进行序列化有这样两个问题

  1. JSON 进行序列化的额外空间开销比较大,对于大数据量服务这意味着需要巨大的内存和磁盘开销
  2. JSON 没有类型,但像 Java 这种强类型语言,需要通过反射统一解决,所以性能不会太好。

如果 RPC 框架选用 JSON 序列化,服务提供者与服务调用者之间传输的数据量要相对较小,否则将严重影响性能。

3、Hessian

我没用过

4、Protobuf

Protobuf 是 Google 公司内部的混合语言数据标准,是一种轻便、高效的结构化数据存储格式,可以用于结构化数据序列化,支持 Java、Python、C++、Go 等语言。Protobuf 使用的时候需要定义 IDL(Interface description language),然后使用不同语言的 IDL 编译器,生成序列化工具类,它的优点是:

  • 序列化后体积相比 JSON、Hessian 小很多;
  • IDL 能清晰地描述语义,所以足以帮助并保证应用程序之间的类型不会丢失,无需类似 XML 解析器;
  • 序列化反序列化速度很快,不需要通过反射获取类型;
  • 消息格式升级和兼容性不错,可以做到向后兼容。

Protobuf 非常高效,但是对于具有反射和动态能力的语言来说,这样用起来很费劲,这一点就不如 Hessian,比如用 Java 的话,这个预编译过程不是必须的,可以考虑使用 Protostuff。

三.如何选择序列化协议:

1、常见的序列化协议有JDK、Hession、Protobuf、JSON、XML;
2、序列化协议的选择指标为序列化性能、序列化后数据大小、协议本身兼容性(协议版本上下兼容性,跨语言兼容性)、安全性。
这几种协议对比如下:
1、JSON、XML,可读性好,但是性能较差,序列化后占用空间大,序列化后数据无类型,需要反射才能获取对象类型;
2、JDK通过InputStream、OutputSteeam来序列化、反序列化,性能也比较差;
3、Hession、Protobuf性能都比较好,Hession对象兼容性更好,Protobuf更加高效。RPC框架一般选用这两种的比较多。