protostuff序列化使用
背景
最近在做项目的时候需要使用持久化功能,1.0版本中使用的akka自带的持久化功能,使用的是akka persist支持的redis插件,在使用的过程中踩了一些坑。因此,在而2.0版本中考虑自己往redis中持久化。要做持久化,必须考虑对象的序列化问题。序列化的方法很多,可以使用java自带的序列化机制,但是时间效率不太好。因此在kryo和protobuffer之间徘徊。因为以前使用过grpc,需要手动编写proto文件,然后利用插件生成代码,觉得很麻烦。但是通过搜索了解到还有一个protostuff不需要编写proto文件这个麻烦的步骤,并且效率还很好。因此,学习了下。
引入依赖
<dependency>
<groupId>io.protostuff</groupId>
<artifactId>protostuff-core</artifactId>
<version>1.6.0</version>
</dependency>
<dependency>
<groupId>io.protostuff</groupId>
<artifactId>protostuff-runtime</artifactId>
<version>1.6.0</version>
</dependency>
javaBean
编写需要序列化和反序列化的对象
public class User {
private String name;
private int age;
public User(String name, int age) {
this.name = name;
this.age = age;
}
}
public class Group {
private String id;
private String name;
private List<User> users;
public Group(String id, String name, List<User> users) {
this.id = id;
this.name = name;
this.users = users;
}
}
开发序列化和反序列化工具类
public class ProtostuffUtils {
/**
* 避免每次序列化都重新申请Buffer空间
*/
private static LinkedBuffer buffer = LinkedBuffer.allocate(LinkedBuffer.DEFAULT_BUFFER_SIZE);
/**
* 缓存Schema
*/
private static Map<Class<?>, Schema<?>> schemaCache = new ConcurrentHashMap<Class<?>, Schema<?>>();
/**
* 序列化方法,把指定对象序列化成字节数组
*
* @param obj
* @param <T>
* @return
*/
@SuppressWarnings("unchecked")
public static <T> byte[] serialize(T obj) {
Class<T> clazz = (Class<T>) obj.getClass();
Schema<T> schema = getSchema(clazz);
byte[] data;
try {
data = ProtostuffIOUtil.toByteArray(obj, schema, buffer);
} finally {
buffer.clear();
}
return data;
}
/**
* 反序列化方法,将字节数组反序列化成指定Class类型
*
* @param data
* @param clazz
* @param <T>
* @return
*/
public static <T> T deserialize(byte[] data, Class<T> clazz) {
Schema<T> schema = getSchema(clazz);
T obj = schema.newMessage();
ProtostuffIOUtil.mergeFrom(data, obj, schema);
return obj;
}
@SuppressWarnings("unchecked")
private static <T> Schema<T> getSchema(Class<T> clazz) {
Schema<T> schema = (Schema<T>) 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 User user1 = new User("aaa",20);
final User user2 = new User("bbb",21);
List<User> users = new ArrayList<User>(){{add(user1);add(user2);}};
Group group = new Group("id_1","group1",users);
byte[] bytes = ProtostuffUtils.serialize(group);
System.out.println("序列化后: " + bytes.length);
Group group1 = ProtostuffUtils.deserialize(bytes,Group.class);
System.out.println("反序列化后: " + group1.getName());
}
运行结果如下:
序列化后: 32
反序列化后: group1
工具类参考博客:https://blog.csdn.net/oppo5630/article/details/80173520
protostuff的github地址:https://github.com/protostuff/protostuff