Protostuff的使用

初探Protostuff的使用

最近在学习RPC,看到了一个叫做Protostuff的库,是基于谷歌Protocal Buffer的序列化库,之前了解过Protocol Buffer,对学习了一些资料后,写了个demo,记录下来。

什么是Protocol Buffer?

Protocol Buffer是谷歌出品的一种数据交换格式,独立于语言和平台,类似于json。Google提供了多种语言的实现:java、c++、go和python。对象序列化城Protocol Buffer之后可读性差,但是相比xml,json,它占用小,速度快。适合做数据存储或 RPC 数据交换格式。

Java序列化库 - Protostuff

相对我们常用的json来说,Protocol Buffer门槛更高,因为需要编写.proto文件,再把它编译成目标语言,这样使用起来就很麻烦。但是现在有了protostuff之后,就不需要依赖.proto文件了,他可以直接对POJO进行序列化和反序列化,使用起来非常简单。

对比

就 易用性 方面先做一个简单的对比:

  • 原生的protobuf,需要手写.proto文件(也就是定义协议),再通过编译生成相应的Java代码,再通过相应的API完成序列化和反序列化。

  • 编译生成的Java代码有上千行,而且对于框架有一点的“入侵性”。

  • protostuff对于POJO支持的很好。 (关于实现原理这里先再埋个坑,猜测是定义了一个通用的协议)

实战

Maven依赖

<dependency>
    <groupId>com.dyuproject.protostuff</groupId>
    <artifactId>protostuff-core</artifactId>
    <version>1.0.7</version>
</dependency>

<dependency>
    <groupId>com.dyuproject.protostuff</groupId>
    <artifactId>protostuff-runtime</artifactId>
    <version>1.0.7</version>
</dependency>

先编写两个POJO,再把它们嵌套起来,这里使用了lombok的@Data注解和@Builder注解,@Data可以自动生成getter setter,@Builder注解可以让我们通过更加优雅的构建者模式来创建对象。

@Data
@Builder
public class User {
    private String id;

    private String name;

    private Integer age;

    private String desc;
}
@Data
@Builder
public class Group {
    private String id;

    private String name;

    private User user;
}

基于protostuff实现一个序列化和反序列化的工具,代替之前Java原生的序列化。
(其实只是对ProtostuffIOUtil做一个简单的封装)

/**
 * 序列化和反序列化工具类
 */
public class SerializingUtil {

    /**
     * 将目标类序列化为byte数组
     *
     * @param source
     * @param <T>
     * @return
     */
    public static <T> byte[] serialize(T source) {
        RuntimeSchema<T> schema;
        LinkedBuffer buffer = null;
        byte[] result;
        try {
            schema = RuntimeSchema.createFrom((Class<T>) source.getClass());
            buffer = LinkedBuffer.allocate(LinkedBuffer.DEFAULT_BUFFER_SIZE);
            result = ProtostuffIOUtil.toByteArray(source, schema, buffer);
        } catch (Exception e) {
            throw new RuntimeException("serialize exception");
        } finally {
            if (buffer != null) {
                buffer.clear();
            }
        }

        return result;
    }

    /**
     * 将byte数组反序列化为目标类
     *
     * @param source
     * @param typeClass
     * @param <T>
     * @return
     */
    public static <T> T deserialize(byte[] source, Class<T> typeClass) {
        RuntimeSchema<T> schema;
        T newInstance;
        try {
            schema = RuntimeSchema.createFrom(typeClass);
            newInstance = typeClass.newInstance();
            ProtostuffIOUtil.mergeFrom(source, newInstance, schema);
        } catch (Exception e) {
            throw new RuntimeException("deserialize exception");
        }

        return newInstance;
    }
}

测试

再用testng写个测试用例验证下。

/**
 * 序列化和反序列化工具测试类
 *
 * @author nathan
 * @date 2019/3/17
 */
public class SerializingUtilTest {

    @Test
    public void test() {
        String expect = "hello, world.";
        byte[] serialized = SerializingUtil.serialize(expect);
        Assert.assertEquals(SerializingUtil.deserialize(serialized, String.class), expect);
    }
}

版权声明:本文为qq_33651286原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。