序列化与反序列化之Protostuff(一)
一 序列化与反序列化
在大型开发中,序列化与反序列化是一个常见的技术点和问题。在之前我们对序列化与反序列化有过相关描述,但并不系统,更偏重于原理介绍。这里,我们将详细介绍序列化与反序列化的更多场景和应用实践。
序列化-protobuf的编码结构二 概念回顾
当两个进程在进行远程通信时,彼此可以发送各种类型的数据。无论是何种类型的数据,都会以二进制序列的形式在网络上传送。发送方需要把这个Java对象转换为字节序列,才能在网络上传送;接收方则需要把字节序列再恢复为Java对象。
把Java对象转换为字节序列的过程称为 对象的序列化 。
把字节序列恢复为Java对象的过程称为 对象的反序列化 。 三技术方案3.1google的protobuffer
早期google原生的protobuffer使用起来相当麻烦,首先要写.proto文件,然后编译.proto文件,生成对应的.java文件,过程较为繁琐。不过目前随着protobuf-java等jar包的提供,使用也简化了很多。github地址:https://github.com/topics/protobuffer。 3.2Java的序列化与反序列化
根据Thinking in java 3rd Edition的描述:
利用对象序列化可以实现"轻量级持久化"(lightweight persistence)。"持久化"意味着一个对象的生存周期并不取决于程序是否正在执行;它可以生存于程序的调用之间。通过将一个序列化对象写入磁盘,然后在重新调用时恢复该对象,就能够实现持久化的效果。之所以称其为"轻量级",是因为不能用某种"persistent"(持久)关键字来简单地定义一个对象,并让系统自动维护其他细节问题(尽管将来有可能实现)。相反,对象必须在程序中显式地序列化和重组。如果需要一个更严格的持久化机制,可以考虑使用Java数据对象(JDO)或者像Hibernate之类的工具。
对象序列化的概念加入到语言中是为了提供对两种主要特性的支持:
·Java的"远程方法调用"(RMI,Remote Method Invocation)使存活于其他计算机上的对象使用起来就像是存活于本机上一样。当向远程对象发送消息时,需要通过对象序列化来传输参数和返回值。
·对Java Beans来说对象序列化也是必需的。使用一个Bean时,一般情况下是在设计阶段对它的状态信息进行配置。这种状态信息必须保存下来,并在程序启动以后,进行恢复;具体工作由对象序列化完成。 3.3io.protostuff
这是最近在项目中使用到的一个框架,本篇也将先详细描述相关的使用案例,作为本系列的开篇。 四使用示例4.1引入maven依赖
使用的是1.5.3版本: io.protostuff protostuff-runtime 1.5.3 io.protostuff protostuff-core 1.5.3 4.2定义实体类4.2.1ProtoBufEntitypackage com.flamingskys.toolbox.tool.protobuf.entity; import lombok.Data; @Data public class ProtoBufEntity { private String name; private int age; private String label; public ProtoBufEntity(){ } public ProtoBufEntity(String name, Integer age){ this.name = name; this.age = age; } }4.2.2GroupEntity
这是一个嵌套实体类,包含了上面的ProtoBufEntity: package com.flamingskys.toolbox.tool.protobuf.entity; import lombok.Data; import java.util.List; @Data public class GroupEntity { private String id; private String name; private List entities; public GroupEntity(String id, String name, List entities) { this.id = id; this.name = name; this.entities = entities; } }4.2.3应用类ProtoStuffUtilspackage com.flamingskys.toolbox.tool.protobuf; import com.flamingskys.toolbox.tool.protobuf.entity.GroupEntity; import com.flamingskys.toolbox.tool.protobuf.entity.ProtoBufEntity; import io.protostuff.LinkedBuffer; import io.protostuff.ProtostuffIOUtil; import io.protostuff.Schema; import io.protostuff.runtime.RuntimeSchema; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; public class ProtoStuffUtils { /** * 避免每次序列化都重新申请Buffer空间 */ private static LinkedBuffer buffer = LinkedBuffer.allocate(LinkedBuffer.DEFAULT_BUFFER_SIZE); /** * 缓存Schema */ private static Map, Schema<?>> schemaCache = new ConcurrentHashMap, Schema<?>>(); /** * 序列化方法,把指定对象序列化成字节数组 * * @param obj * @param * @return */ @SuppressWarnings("unchecked") public static byte[] serialize(T obj) { Class clazz = (Class) obj.getClass(); Schema schema = getSchema(clazz); byte[] data; try { data = ProtostuffIOUtil.toByteArray(obj, schema, buffer); } finally { buffer.clear(); } return data; } /** * 反序列化方法,将字节数组反序列化成指定Class类型 * * @param data * @param clazz * @param * @return */ public static T deserialize(byte[] data, Class clazz) { Schema schema = getSchema(clazz); T obj = schema.newMessage(); ProtostuffIOUtil.mergeFrom(data, obj, schema); return obj; } @SuppressWarnings("unchecked") private static Schema getSchema(Class clazz) { Schema schema = (Schema) schemaCache.get(clazz); if (schema == null) { //这个schema通过RuntimeSchema进行懒创建并缓存 //所以可以一直调用RuntimeSchema.getSchema(),这个方法是线程安全的 schema = RuntimeSchema.getSchema(clazz); if (schema == null) { schemaCache.put(clazz, schema); } } return schema; } public static void main(String[] args){ final ProtoBufEntity entity1 = new ProtoBufEntity("aaa",20); final ProtoBufEntity entity2 = new ProtoBufEntity("bbb",21); List entitys = new ArrayList(){ { add(entity1); add(entity2); } }; GroupEntity group = new GroupEntity("id_1","group1", entitys); byte[] bytes = ProtoStuffUtils.serialize(group); System.out.println("序列化后: " + bytes.length); GroupEntity group1 = ProtoStuffUtils.deserialize(bytes,GroupEntity.class); System.out.println("反序列化后: " + group1.getName()); } }