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

posted on 2019-04-25 14:38  junjiang3  阅读(1088)  评论(0编辑  收藏  举报