1.序列化和反序列化
序列化: 将对象序列化为二进制数据(字节数组),一般也将序列化称为编码(Enccode),主要用于网络传输,数据持久化。
反序列化: 将从网络上,磁盘等读取的字节数组还原成原始对象,一般也将反序列化称为解码(Decode),主要用于网络传输对象的解码,以便完成远程调用。
2.选择序列化协议时,需要考虑什么?
- 序列化之后的码流大小(占用网络带宽)
- 序列化和反序列化的性能(cpu资源占用)
- 是否支持跨语言
3.测试Java自带的序列化类
objectoutputstream /objectInputstream是Java自带的序列化类,测试它序列化的效率。
Teacher类是待序列化的类,它的定义如下:
import java.io.Serializable;
public class Teacher implements Serializable{
private static final long serialVersionnUID = 8619259453444471644L;
private Long id;
private int age;
private String name;
public Teacher(Long id,int age,String name ){
this.id = id;
this.age = age;
this.name = name;
}
}
序列化和反序列化的定义如下:
import java.io.ByteArrayOutputStream;
import java.io.ByteArrayInputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.Arrays;
import java.io.Serializable;
public class TestJavaSerializer
{
//序列化
private static byte[] serialize(Teacher t) throws Exception{
ByteArrayOutputStream out = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(out);
oos.writeObject(t);
byte[] array = out.toByteArray();
return array;
}
//反序列化
private static Teacher deserialize(byte[] byteArray) throws Exception{
ByteArrayInputStream ins = new ByteArrayInputStream(byteArray);
ObjectInputStream ois = new ObjectInputStream(ins);
Teacher t = (Teacher)ois.readObject();
return t;
}
public static void main(String []args) throws Exception{
Teacher t = new Teacher(1L, 22, "April");
byte[] byteArray = serialize(t);
System.out.println(Arrays.toString(byteArray));
System.out.println("Length = " + byteArray.length);
Teacher t1 = deserialize(byteArray);
}
}
输出结果如下:
[-84, -19, 0, 5, 115, 114, 0, 7, 84, 101, 97, 99, 104, 101, 114, -19, 83, 98, -77, 62, -23, 40, 8, 2, 0, 3, 73, 0, 3, 97, 103, 101, 76, 0, 2, 105, 100, 116, 0, 16, 76, 106, 97, 118, 97, 47, 108, 97, 110, 103, 47, 76, 111, 110, 103, 59, 76, 0, 4, 110, 97, 109, 101, 116, 0, 18, 76, 106, 97, 118, 97, 47, 108, 97, 110, 103, 47, 83, 116, 114, 105, 110, 103, 59, 120, 112, 0, 0, 0, 22, 115, 114, 0, 14, 106, 97, 118, 97, 46, 108, 97, 110, 103, 46, 76, 111, 110, 103, 59, -117, -28, -112, -52, -113, 35, -33, 2, 0, 1, 74, 0, 5, 118, 97, 108, 117, 101, 120, 114, 0, 16, 106, 97, 118, 97, 46, 108, 97, 110, 103, 46, 78, 117, 109, 98, 101, 114, -122, -84, -107, 29, 11, -108, -32, -117, 2, 0, 0, 120, 112, 0, 0, 0, 0, 0, 0, 0, 1, 116, 0, 5, 65, 112, 114, 105, 108]
Length = 176
使用Java自带的序列化类objectoutputstream /objectInputstream对Teacher对象序列化后的长度为176。
4.Protobuf序列化
用proto文件定义Teacher类,文件名为Teacher.proto,使用命令生成TeacherSerializer.java文件。
syntax = "proto2";
option java_package = "com.netty.protobuf";
option java_outer_classname = "TeacherSerializer";
message Teacher{
required int64 id = 1;
required int32 age =2;
required string name = 3;
}
序列化和反序列化的定义如下:
package com.netty.protobuf;
import java.util.Arrays;
import com.netty.protobuf.TeacherSerializer.Teacher;
import com.netty.protobuf.TeacherSerializer.Teacher.Builder;
public class TestProtobuf {
//序列化
private static byte[] serialize()
{
Builder builder = TeacherSerializer.Teacher.newBuilder();
builder.setId(1L).setAge(22).setName("April");
Teacher t = builder.build();
return t.toByteArray();
}
//反序列化
private static Teacher deserialize(byte[] data) throws Exception
{
Teacher t = TeacherSerializer.Teacher.parseFrom(data);
return t;
}
public static void main(String[] args) throws Exception {
byte[] data = serialize();
System.out.println(Arrays.toString(data));
System.out.println("Length = " + data.length);
Teacher t = deserialize(data);
}
}
输出结果如下:
[8, 1, 16, 22, 26, 5, 65, 112, 114, 105, 108]
Length = 11
使用Protobuf对Teacher对象序列化后的长度为11。序列化后的数据长度比java自带的序列化类短了很多。
5.结论
使用Java自带的序列化类objectoutputstream /objectInputstream对Teacher对象序列化后的长度为176。而使用Protobuf序列化后的长度仅为11。占用带宽和消耗CPU都会比较小,所以使用Protobuf效率更高。