概述
protobuf(也叫做pb)是谷歌开源的一款序列化、反序列化的框架,由于其出色的效率、高效的编码格式使得
数据在序列化、反序列化以及传输的过程中有很大的优势,因此在rpc数据交换或者数据存储中有很好的应用。
优点:
- 高效:这里的高效是指其在序列化、反序列化的过程中占用的时间特别少,究其原因是因为其只在字节流和对象之间进行转换,相较于其他的序列化、反序列化的框架如json,还要把对象组织称用户易于读懂的格式
- 节省带宽:由于其高效的编码方式,使得序列化之后的数据占用的空间特别小
缺点:
- 不易读懂:鉴于其高效的编码格式,使得数据在序列化或者反序列化之后很难读懂,也正因为如此,我们基本上没有在涉及前段开发的过程中使用pb这种协议来传输数据
示例
笔者所用的语言是java,因此演示示例也适用java来演示。官网上有演示如何使用pb来定义java对象以及如何使用,不过很遗憾,
这种演示方式在真正构建大型工程的时候很难,因为我们总不能把pb文件一个一个的编译,然后考到指定的目录,这有点不切实际,
大型的项目更多的是会使用maven的插件来进行构建整个工程,如下演示如何使用maven插件来构建,工程的整体结构如下图所示:
如下为maven需要的依赖:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43
| <dependencies> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.11</version> <scope>test</scope> </dependency> <dependency> <groupId>com.google.protobuf</groupId> <artifactId>protobuf-java</artifactId> <version>3.4.0</version> </dependency> </dependencies>
<build> <extensions> <extension> <groupId>kr.motd.maven</groupId> <artifactId>os-maven-plugin</artifactId> <version>1.4.1.Final</version> </extension> </extensions> <plugins> <plugin> <groupId>org.xolstice.maven.plugins</groupId> <artifactId>protobuf-maven-plugin</artifactId> <version>0.5.0</version> <configuration> <protocArtifact> com.google.protobuf:protoc:3.1.0:exe:${os.detected.classifier} </protocArtifact> <pluginId>grpc-java</pluginId> </configuration> <executions> <execution> <goals> <goal>compile</goal> </goals> </execution> </executions> </plugin> </plugins> </build>
|
接下来我们使用protobuf3来编写一个模型
1 2 3 4 5 6 7 8 9 10
| syntax = "proto3";
option java_package = "com.h3c"; option java_outer_classname = "PersonBuilder";
message Person { int32 id = 1; string name = 2; string email = 3; }
|
然后我们使用pb的插件来生成对应的Java类,生成的java类最终会在target目录下,不过我们的工程是可以引用到的,如下:

这里需要注意,pom文件中的protoc版本最好和本机安装的保持一直,这样可以直接使用mvn clean install命令来生成对应的类,因为我自己在使用的时候发现
会报错:
1
| protoc-gen-grpc-java: program not found or is not executable
|
这是因为网上的一些教程通常会指定:
1
| <goal>compile-custom</goal>
|
选项,将这个选项去掉后就可以正常的打包了。
最后我们就可以在工程中引用这些类,测试代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| public class App { public static void main(String[] args) throws InvalidProtocolBufferException { PersonBuilder.Person.Builder builder = PersonBuilder.Person.newBuilder(); PersonBuilder.Person person = builder.setId(1) .setName("wes") .setEmail("wes@gmail.com").build(); byte[] pb = person.toByteArray();
for (byte b : pb) { System.out.println(b); }
PersonBuilder.Person p1 = PersonBuilder.Person.parseFrom(pb); System.out.println(p1); } }
|
对应的测试结果如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| 8 1 18 3 119 101 115 26 13 119 101 115 64 103 109 97 105 108 46 99 111 109 id: 1 name: "wes" email: "wes@gmail.com"
|
总结
相较于json这种序列化仅仅包含字符串和数字类型,pb的类型则要丰富的多(不过pb的模型应该是不具备继承特性的,后续补充),具体可以参考以下文章:
[pb终极教程] https://colobu.com/2019/10/03/protobuf-ultimate-tutorial-in-go/