使用Protostuff实现序列化与反序列化
(1)Protobuf介绍
Google Protocol Buffer( 简称 Protobuf) 是 Google 公司内部的混合语言数据标准,目前已经正在使用的有超过 48,162 种报文格式定义和超过 12,183 个 .proto 文件。他们用于 RPC 系统和持续数据存储系统。
Protocol Buffers 是一种轻便高效的结构化数据存储格式,可以用于结构化数据串行化,或者说序列化。它很适合做数据存储或 RPC 数据交换格式。可用于通讯协议、数据存储等领域的语言无关、平台无关、可扩展的序列化结构数据格式。目前提供了 C++、Java、Python 三种语言的 API。
(2)Protobuf优点
平台无关,语言无关,可扩展;
提供了友好的动态库,使用简单;
解析速度快,比对应的XML快约20-100倍;
序列化数据非常简洁、紧凑,与XML相比,其序列化之后的数据量约为1/3到1/10;
独立于语言,独立于平台,最最重要的是它的效率相当高,用protobuf序列化后的大小是json的10分之一,xml格式的20分之一,是二进制序列化的10分之一,
(3)Protobuf主要流程
需要自己写一个.proto文件用来描述序列化的格式,然后用Protobuf提供的protoc工具将.proto文件编译成一个Java文件,最后将该Java文件引入到项目中就可以了。
(4)Protostuff介绍
google原生的protobuffer使用起来相当麻烦,首先要写.proto文件,然后编译.proto文件,生成对应的.java文件。protostuff基于Google Protobuf,好处就是不用自己写.proto文件同时在几乎不损耗性能的情况下即可实现对象的序列化与反序列化。
(5)使用Protostuff示例
Protostuff版本:
使用Protostuff实现Jedis中Club对象的读取:
代码结构为:
序列化工具类ProtostuffSerializer 提供了序列化和反序列化方法:
// 序列化工具
public byte[] seriable(final Club club) {
final LinkedBuffer linkedBuffer = LinkedBuffer.allocate(LinkedBuffer.DEFAULT_BUFFER_SIZE);
try {
return serializeInternal(club, schema, linkedBuffer);
} catch (final Exception e) {
throw new IllegalStateException(e.getMessage(), e);
} finally {
linkedBuffer.clear();
}
}
// 实际序列化工具
private
return ProtostuffIOUtil.toByteArray(source, schema, linkedBuffer);
}
// 反序列化工具
public Club deserialize(final byte[] bytes) {
try {
Club club = deserializeInternal(bytes, schema.newMessage(), schema);
if (club != null) {
return club;
}
} catch (final Exception e) {
throw new IllegalStateException(e.getMessage(), e);
}
return null;
}
// 实际反序列化工具
private
ProtostuffIOUtil.mergeFrom(bytes, result, schema);
return result;
}
应用:
io.protostuff protostuff-core 1.6.0 io.protostuff protostuff-runtime 1.6.0
package com.java.mailbox.utils; import io.protostuff.LinkedBuffer; import io.protostuff.ProtobufIOUtil; import io.protostuff.ProtostuffIOUtil; import io.protostuff.Schema; import io.protostuff.runtime.RuntimeSchema; /** * @Author: 束手就擒 * @Date: 18-8-25 下午8:05 * @Description: */ public class ObjectSerializeUtil { /** * 序列化 * @param o * @param* @return */ @SuppressWarnings("unchecked") public static byte[] serializer(T o) { Schema schema = RuntimeSchema.getSchema(o.getClass()); return ProtobufIOUtil.toByteArray(o, schema, LinkedBuffer.allocate(256)); } /** * 反序列化 * @param bytes * @param clazz * @param * @return */ @SuppressWarnings("unchecked") public static T deserializer(byte[] bytes, Class clazz) { T obj = null; try { obj = clazz.newInstance(); Schema schema = RuntimeSchema.getSchema(obj.getClass()); ProtostuffIOUtil.mergeFrom(bytes, obj, schema); } catch (IllegalAccessException | InstantiationException e) { e.printStackTrace(); } return obj; } }
测试:
package com.java.mailbox.obj; import com.java.mailbox.utils.ObjectSerializeUtil; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.context.junit4.SpringRunner; import java.util.Arrays; import static org.junit.Assert.*; /** * @Author: 束手就擒 * @Date: 18-8-25 下午8:36 * @Description: */ @RunWith(SpringRunner.class) @SpringBootTest public class StudentTest { @Test public void hhh() { Student student = Student.builder().userName("束手就擒") .userAge(20) .userGender("Male") .build(); byte[] serializate = ObjectSerializeUtil.serializer(student); System.out.println("serialize = "+ Arrays.toString(serializate)); Student studentB = ObjectSerializeUtil.deserializer(serializate,Student.class); System.out.println("studentB = "+studentB.toString()); } }
结果:
2018-08-25 21:05:00.045 INFO 7815 --- [ main] com.java.mailbox.obj.StudentTest : Started StudentTest in 11.407 seconds (JVM running for 14.519)
serialize = [10, 12, -26, -99, -97, -26, -119, -117, -27, -80, -79, -26, -109, -110, 18, 4, 77, 97, 108, 101, 24, 20]
studentB = Student(userName=束手就擒, userGender=Male, userAge=20)