详解Protobuf序列化协议的使用

Protobuf是谷歌推出的一款平台无关的序列化协议,相比传统的序列化方式,Protobuf体积更小,更灵活,能有效提高传输效率,减少数据传输过程中占用的带宽。简单来说,Protobuf有以下特点:

语言无关、平台无关。Protobuf支持Java、C++、Python等多种语言,多个平台
高效。比 XML 更小(3 ~ 10倍)、更快(20 ~ 100倍)、更为简单
扩展性、兼容性好。你可以更新数据结构,而不影响和破坏原有的旧程序

本文以Animal实体类为例,感受protobuf的特点;

public class Animal implements Serializable {
     

    private Long id;
    private String name;
    private List<String> actions;
    
	/**省略get、set方法**/
}

1.使用Protobuf

创建AnimalProto.proto,定义的数据类型如下:

package com.keduw.protobuf;

message Animal{
     
    //id
    required int64 id = 1;
    //name
    optional string name = 2;
    //actions
    repeated string actions = 3;
}

Protobuf定义了它自己的语法规则。package定义我们最后生成Java代码所属的包,required表示该字段是必填的,optional表示该字段是可选的,而repeated则标明该字段是可连续的,对应到Java中则表示一个集合,通过定义字段的顺序方便Protobuf对字段的反序列化。具体对应的数据类型可以参考如下:
详解Protobuf序列化协议的使用_第1张图片
编写好AnimalProto.proto,可以通过官网提供的protoc.exe生成对应的Java代码(如果找不到可在文章末尾下载)。

2.序列化和反序列化

前面通过工具生成的代码(AnimalProto)已经帮我们封装好了序列化和反序列化的方法,我们只需要调用对应方法即可。

引入Protobuf的依赖

<dependency>
    <groupId>com.google.protobuf</groupId>
    <artifactId>protobuf-java</artifactId>
    <version>2.4.1</version>
</dependency>

序列化:

/**
 * 调用对象构造好的Builder,完成属性赋值和序列化操作
 * @return
 */
public static byte[] protobufSerializer(){
     
    AnimalProto.Animal.Builder builder = AnimalProto.Animal.newBuilder();
    builder.setId(1L);
    builder.setName("小猪");
    List<String> actions = new ArrayList<>();
    actions.add("eat");
    actions.add("run");
    builder.addAllActions(actions);
    return builder.build().toByteArray();
}

反序列化:

/**
 * 通过调用parseFrom则完成反序列化
 * @param bytes
 * @return
 * @throws InvalidProtocolBufferException
 */
public static Animal deserialize(byte[] bytes) throws Exception {
     
    AnimalProto.Animal pAnimal = AnimalProto.Animal.parseFrom(bytes);
    Animal animal = new Animal();
    animal.setId(pAnimal.getId());
    animal.setName(pAnimal.getName());
    animal.setActions(pAnimal.getActionsList());
    return animal;
}

测试:

public static void main(String[] args) throws Exception {
     
    byte[] bytes = serializer();
    Animal animal = deserialize(bytes);
    System.out.println(animal);
}

可以看到是能正常序列化和反序列化的。详解Protobuf序列化协议的使用_第2张图片

3.性能对比

另外,我在这里还单独对比了Java原生序列化、jackson和Protobuf序列化对同一个数据Animal操作后的数据长度,可以看到Protobuf序列化后的长度是明显比较小,可见Protobuf的性能还是很优秀的。
详解Protobuf序列化协议的使用_第3张图片
至于Protobuf为什么能做到这些提高,这跟他自己定义的数据结构有关系,对于不同的数据类型采用了不同的序列化方式,对实现原理感兴趣的可以自行再了解。

本文源代码以及*.proto文件的转换工具:【下载】

你可能感兴趣的:(分布式,微服务,protobuf,网络协议,java)