一文读懂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方法**/
}

一、使用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对字段的反序列化。具体对应的数据类型可以参考如下:
在这里插入图片描述
编写好AnimalProto.proto,可以通过官网提供的protoc.exe生成对应的Java代码(如果找不到可在文章末尾下载)。

二、序列化和反序列化

前面通过工具生成的代码(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);
}

可以看到是能正常序列化和反序列化的。在这里插入图片描述

三、性能对比

另外,我在这里还单独对比了Java原生序列化、jackson和Protobuf序列化对同一个数据Animal操作后的数据长度,可以看到Protobuf序列化后的长度是明显比较小,可见Protobuf的性能还是很优秀的。
在这里插入图片描述
至于Protobuf为什么能做到这些提高,一方面通过定义字段顺序完成数据映射,因此不用保存字段名,另一方面,这跟他自己定义的数据结构也有关系,对于不同的数据类型采用了不同的序列化方式,对实现原理感兴趣的可以自行了解。

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

ProtoBuf是一种数据序列化和反序列化的技术,它的全称是Protocol Buffers。ProtoBuf可以将结构化数据转换为二进制格式,以便在不同的系统之间进行高效的数据交换。使用ProtoBuf进行序列化和反序列化有以下几个优势: 1. 空间效率:ProtoBuf使用紧凑的二进制编码格式,可以大大减少数据的存储空间。相比于传统的文本格式如XML和JSON,ProtoBuf的数据大小通常要小得多。 2. 时间效率:ProtoBuf的解析和生成代码都是使用高效的机器生成,因此在序列化和反序列化过程中可以获得更快的速度。特别是在处理大规模数据时,ProtoBuf的效率更加显著。 3. 可读性:虽然ProtoBuf的数据是以二进制形式存储的,但是它的定义文件是以文本形式进行编写的,具有良好的可读性和可维护性。开发人员可以通过阅读ProtoBuf定义文件了解数据结构的字段和类型。 在前后端交互中,ProtoBuf可以作为一种通用的数据交换格式。前端可以将数据序列化ProtoBuf格式,然后发送给后端进行处理。后端可以将接收到的ProtoBuf数据反序列化为对象,然后进行相应的业务逻辑处理。 下面是使用ProtoBuf进行序列化和反序列化的示例代码: ```java // 创建一个user对象 User user = User.builder().id("1").age(20).name("张三").desc("programmer").build(); // 创建一个Group对象,将user放入group中 Group group = Group.builder().id("1").name("分组1").user(user).build(); // 使用ProtostuffUtils序列化 byte[] data = ProtostuffUtils.serialize(group); System.out.println("序列化后:" + Arrays.toString(data)); // 使用ProtostuffUtils反序列化 Group result = ProtostuffUtils.deserialize(data, Group.class); System.out.println("反序列化后:" + result.toString()); ``` 在上述代码中,首先创建了一个User对象和一个Group对象,然后使用ProtostuffUtils对Group对象进行序列化,将其转换为字节数组。接着使用ProtostuffUtils对字节数组进行反序列化,将其转换为Group对象。最后输出反序列化后的Group对象。 引用:
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

自平衡Azure

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值