序列化机制可以把对象转化成字节数组,将字节数组还原为对象称为反序列化。序列化常用于网络传输对象或存储对象,RPC(远程过程调用)函数调用的参数和结果就是通过序列化成字节数组传递的。
java内置的序列化能将实现了Serilazable接口的对象进行序列化和反序列化,ObjectOutputStream的writeObject()方法可序列化对象生成字节数组
ByteArrayOutputStream bytes = new ByteArrayOutputStream();
ObjectOutputStream out = new ObjectOutputStream(bytes);
out.writeObject(obj);
byte[] bytes = bytes.toByteArray();
ObjectInoputStream的readObject()方法可将字节数组还原成对象
ObjectInputStream in = new ObjectInputStream(new ByteArrayInputStream(bytes));
Object obj = in.readObject();
由于java内置的序列化工具性能不尽如人意,并且生成的字节数组较大、不能跨语言,出现了很多第三方序列化工具
Hessian是常用的第三方序列化工具,由于其简单高效特点而使用广泛。hessian序列化的使用方法和java内置的序列化差不多,需要对象实现Serilazable接口,然后调用Hessian的writeObject()方法,就可以生成字节数组
ByteArrayOutputStream bytes = new ByteArrayOutputStream();
Hessian2Output out = new Hessian2Output(bytes);
SerializerFactory serializerFactory = SerializerFactory.createDefault();
out.setSerializerFactory(serializerFactory);
out.writeObject(obj);
out.close();
byte[] bytes = bytes.toByteArray();
Hessian2Input的readObject()方法可将字节数组还原成对象
Hessian2Input in = new Hessian2Input(new ByteArrayInputStream(bytes));
SerializerFactory serializerFactory = SerializerFactory.createDefault();
in.setSerializerFactory(serializerFactory);
Object obj = in.readObject();
in.close();
google开源的protobuf采用更为紧凑的二进制数组,表现更加优异,不过其使用方法极其繁琐,需要编写proto文件,然后使用protobuf的编译工具生成pojo类
LinkedBuffer buffer = LinkedBuffer.allocate(LinkedBuffer.DEFAULT_BUFFER_SIZE);
Schema schema = RuntimeSchema.createFrom(T.class);
byte[] bytes = ProtostuffIOUtil.toByteArray(obj, schema, buffer);
反序列化也需要添加模式schema,然后调用ProtostuffIOUtil的mergeFrom()方法即可将字节还原成对象
T obj = T.class.newInstance();
Schema schema = RuntimeSchema.createFrom(T.class);
ProtostuffIOUtil.mergeFrom(bytes, obj, schema);
下面对三种工具进行性能测试,对一个较大的对象BigPojo序列化和反序列化2000次
public static byte[] JavaSerialize(BigPojo obj) throws IOException//java内置序列化
{
ByteArrayOutputStream bytes = new ByteArrayOutputStream();
ObjectOutputStream out = new ObjectOutputStream(bytes);
out.writeObject(obj);
return bytes.toByteArray();
}
public static BigPojo JavaDeserialize(byte[] bytes) throws Exception//java内置反序列化
{
ObjectInputStream in = new ObjectInputStream(new ByteArrayInputStream(bytes));
return (BigPojo) in.readObject();
}
public static byte[] HessianSerialize(BigPojo obj) throws Exception//hessian序列化
{
ByteArrayOutputStream bytes = new ByteArrayOutputStream();
Hessian2Output out = new Hessian2Output(bytes);
SerializerFactory serializerFactory = SerializerFactory.createDefault();
out.setSerializerFactory(serializerFactory);
out.writeObject(obj);
out.close();
return bytes.toByteArray();
}
public static BigPojo HessianDeserialize(byte[] bytes) throws Exception//hessian反序列化
{
Hessian2Input in = new Hessian2Input(new ByteArrayInputStream(bytes));
SerializerFactory serializerFactory = SerializerFactory.createDefault();
in.setSerializerFactory(serializerFactory);
BigPojo obj = (BigPojo) in.readObject();
in.close();
return obj;
}
public static byte[] ProtostuffSerialize(BigPojo obj)//protostuff序列化,已获得模式schema
{
LinkedBuffer buffer = LinkedBuffer.allocate(LinkedBuffer.DEFAULT_BUFFER_SIZE);
return ProtostuffIOUtil.toByteArray(obj, schema, buffer);
}
public static BigPojo ProtostuffDeserialize(byte[] bytes) throws Exception//protostuff反序列化
{
BigPojo obj = BigPojo.class.newInstance();
ProtostuffIOUtil.mergeFrom(bytes, obj, schema);
return obj;
}
测试结果:
hessian: 81ms 50ms 131ms 186字节
protostuff: 20ms 28ms 48ms 93字节
结果显示,在性能和生成字节数大小上,java内置的序列化工具最差,hessian稍好,protostuff最优