protobuf Protocol Buffers 简介 案例

简介

Protocol Buffers (a.k.a., protobuf) 是Google用于序列化结构化数据(比如Java中的Object和C中的Structure)的语言中立、平台中立、可扩展的机制。

Protocol Buffers是Google开发一种数据描述语言,是一种语言无关、平台无关、可扩展的序列化结构数据格式 ,可用于数据存储、通信协议等方面
简单来说,Protocol Buffers可以理解为是更快、更简单、更小的JSON或者XML,区别在于Protocol Buffers是二进制格式,而JSON和XML是文本格式。

相对于XML,Protocol Buffers的具有如下几个优点:
  • 简洁,具有更少的歧义性
  • 体积小,消息大小只需要XML的1/10 ~ 1/3
注意protobuf传输的是对象的二级制内容,而非编译前的 .proto文件,更非编译后的Java源文件,.proto文件只是为了方便阅读、调试和编辑用的
而json和xml传输的就是你看到的json和xml文本内容(字符串)
x
1
注意protobuf传输的是对象的二级制内容,而非编译前的 .proto文件,更非编译后的Java源文件,.proto文件只是为了方便阅读、调试和编辑用的
2
而json和xml传输的就是你看到的json和xml文本内容(字符串)
  • 速度快,解析速度比XML快20 ~ 100倍
  • 自动生成数据访问类方便应用程序的使用
  • 更好的兼容性,Protocol Buffers设计的一个原则就是要能够很好的支持向下或向上兼容

PS:从 protoc 命令支持的参数可以看出目前 protobuf 支持的语言:
包括:C++、C#、Java、JS、OC、PHP、Ruby这七种编程语言。

Protobuf 的优缺点

Protobuf 的优点
  • Protobuf 有如 XML,不过它更小、更快、也更简单。你可以定义自己的数据结构,然后使用代码生成器生成的代码来读写这个数据结构。你甚至可以在无需重新部署程序的情况下更新数据结构。只需使用 Protobuf 对数据结构进行一次描述,即可利用各种不同语言或从各种不同数据流中对你的结构化数据轻松读写。
  • 它有一个非常棒的特性,即向后兼容性好,人们不必破坏已部署的、依靠“老”数据格式的程序就可以对数据结构进行升级。这样您的程序就可以不必担心因为消息结构的改变而造成的大规模的代码重构或者迁移的问题。因为添加新的消息中的 field 并不会引起已经发布的程序的任何改变
  • Protobuf 语义更清晰,无需类似 XML 解析器的东西,因为 Protobuf 编译器会将 .proto 文件编译生成对应的数据访问类以对 Protobuf 数据进行序列化、反序列化操作。
  • 使用 Protobuf 无需学习复杂的文档对象模型,Protobuf 的编程模式比较友好,简单易学,同时它拥有良好的文档和示例,对于喜欢简单事物的人们而言,Protobuf 比其他的技术更加有吸引力。

Protobuf 的不足
  • Protbuf 与 XML 相比也有不足之处。它功能简单,无法用来表示复杂的概念。
  • XML 已经成为多种行业标准的编写工具,Protobuf 只是 Google 公司内部使用的工具,在通用性上还差很多。
  • Protobuf 不适合用来描述一个基于文本的标记型文档(比如HTML),因为你无法轻易的交错文本的结构。另外,XML具有很好的可读性和可编辑性,而protocol buffers,至少在它们的原生形式上并不具备这个特点。XML同时也是可扩展、自描述的,而一个protocol buffer只有在具有message 定义(在.proto文件中定义)时才会有意义。

proto3简介

我们最新的版本version 3 alpha release引进了一个新的语言版本--Protocol Buffers version 3 (称之为proto3),它在我们现存的语言版本(proto2)上引进了一些新特性。proto3简化了protocol buffer language,这使其可以更便于使用和支持更多的编程语言:我们现在的alpha release版本可以让你能产生JAVA、C++、Pthyon、JavaNano、Ruby、Objective-C和C#版本的protocol buffer code,不过可能有时会有一些局限性。另外,你可以使用最新的Go protoc插件来产生Go语言版本的proto3 code,这可以从golang/protobuf Github repository获取。

以下情况下,我们现在只推荐你使用proto3:
  • 如果你想尝试在我们新支持的语言中使用protocol buffers
  • 如果你想尝试我们最新开源的RPC实现gRPC(目前仍处于alpha release版本),我们建议你为所有的 gRPC 服务器和客户端都使用proto3以避免兼容性问题。

注意两个版本的语言APIs并不是完全兼容的,为了避免给原来的用户造成不便,我们将会继续维护之前的那个proto2版本。

使用步骤

1、下载protobuf编译器
下载路径: https://github.com/google/protobuf/releases  ,注意这个东西在每个版本的下载部分的最下面(例如 protoc-3.6.1-win32.zip ):
 
它包含 protoc 二进制文件以及与 protobuf 一起分发的一组标准 .proto文件。

解压后可以把【protoc.exe】所在的目录加入系统变量Path,例如【C:\Android\protobuf\protoc-3.6.1-win32\bin】
然后可以在任何路径测试【protoc】命令是否可用,例如:
protoc --version
libprotoc 3.6.1
1
protoc --version
2
libprotoc 3.6.1

2、添加所选编程语言的 protobuf runtime
确保 runtime 的版本号与 protoc 的版本号匹配(或者版本更新)。

方式一:下载源码,下载路径同上: https://github.com/google/protobuf/releases ,最新版本为 3.6.1
下载后将需要的源码一起复制到项目中 (连同包名),需要的源码一般在以下目录中:
【protobuf-3.6.1\java\core\src\main\java\ com\google\protobuf】(核心包)
【protobuf-3.6.1\java\util\src\main\java\ com\google\protobuf\util】(可选包,提供 protobuf JsonFormat 等功能)

方式二:直接添加protobuf依赖即可,版本号要比使用的 protoc.exe 版本相同或更高:
implementation 'com.google.protobuf:protobuf-java:3.6.1'//protobuf
implementation 'com.google.protobuf:protobuf-java-util:3.6.1'//可选,protobuf JsonFormat 等功能
x
 
1
implementation 'com.google.protobuf:protobuf-java:3.6.1'//protobuf
2
implementation 'com.google.protobuf:protobuf-java-util:3.6.1'//可选,protobuf JsonFormat 等功能

2、编写 .proto 文件
syntax = "proto3";//指定编译时所使用的 protoc 语法版本,不指定时会有WARNING提示:默认使用 proto2。proto3语法更严格。
option java_package = "com.bqt.test.protomodel";//生成的类的包名
option java_outer_classname = "PersonEntity";//生成的类名
message Person { //真正用来封装数据的内部类的类名
  int32 id = 1;
  string name = 2;
  string email = 3;
}
x
1
syntax = "proto3";//指定编译时所使用的 protoc 语法版本,不指定时会有WARNING提示:默认使用 proto2。proto3语法更严格。
2
option java_package = "com.bqt.test.protomodel";//生成的类的包名
3
option java_outer_classname = "PersonEntity";//生成的类名
4
message Person { //真正用来封装数据的内部类的类名
5
  int32 id = 1;
6
  string name = 2;
7
  string email = 3;
8
}

3、编译 .proto 文件生成 java 类
通过protoc命令编译.proto文件生成java类:
protoc -I=目录1 --java_out=目录2 文件3
1
protoc -I=目录1 --java_out=目录2 文件3
  • -I=目录1】或【--proto_path=目录1:输入目录。指定搜索导入的目录。可多次指定,目录将按顺序搜索。如果没有给出,则使用当前工作目录。
  • 【--java_out=目录2】:输出目录。指定生成的Java源文件的目录
  • 【文件3】:从文件中读取选项和文件名。如果指定了相对文件路径,则将在工作目录[working directory]中搜索该文件。--proto_path 选项不会影响搜索此参数文件的方式。文件内容将在参数列表中的 @<filename> 位置展开。 请注意,shell扩展不会应用于文件的内容(即,您不能使用引号、通配符、转义、命令[quotes, wildcards, escapes, commands]等)。 每行对应一个参数,即使它包含空格。

例如:
protoc -I=D:\bqt\proto --java_out=D:\bqt\out test.proto
 
1
protoc -I=D:\bqt\proto --java_out=D:\bqt\out test.proto
如果在当前目录执行命令,可以简化为:
protoc --java_out=D:\bqt\out test.proto
x
 
1
protoc --java_out=D:\bqt\out test.proto

执行上面代码后会发现,在指定的目录下面生成了包含包名的PersonEntity.java类(将近1000行代码)。

4、测试生成的java类
将生成的 java 类复制到项目指定包中,然后可以很方便的调用封装好的Java类的API:
PersonEntity.Person person = PersonEntity.Person.newBuilder()
		.setId(3)
		.setName("zhangsan")
		.setEmail("[email protected]")
		.build();
Log.i("bqt", "对象内容:" + person.toString());
1
PersonEntity.Person person = PersonEntity.Person.newBuilder()
2
        .setId(3)
3
        .setName("zhangsan")
4
        .setEmail("[email protected]")
5
        .build();
6
Log.i("bqt", "对象内容:" + person.toString());

Android中使用建议

对于Android用户,由于其较小的代码大小,建议使用protobuf Java Lite运行时。Java Lite运行时也可以与Proguard一起使用,因为它不依赖于Java反射,并且已经过优化以允许尽可能多的代码剥离[code stripping]。 您可以按照这些说明使用Java Lite运行时。

Protobuf Java Lite运行时与主Java运行时分离,因为它是使用不同的约束设计/实现的(意思是相互不兼容,而不是子集) 。特别是,Java Lite运行时具有更小的代码大小,使其更适合在Android上使用。

要使用Java Lite运行时,需要为Java Lite运行时安装protoc和protoc插件。protoc的配置和上面一致,protoc插件可以从maven下载:
选择适用于您的平台的版本,例如,在Windows上,您可以下载 protoc-gen-javalite-3.0.0-windows-x86_64.exe,将其重命名为protoc-gen-javalite(在Windows上重命名为 protoc-gen-javalite.exe),并将其放在可以在PATH中找到的目录中(例如我也放到之前 protoc.exe所在目录中)。

拥有 protoc 和 protoc 插件后,您可以为 .proto 文件生成 Java Lite 代码:
例如:
//protoc -I=D:\bqt\proto --java_out=D:\bqt\out test.proto
protoc -I=D:\bqt\proto --javalite_out=D:\bqt\out test.proto
x
 
1
//protoc -I=D:\bqt\proto --java_out=D:\bqt\out test.proto
2
protoc -I=D:\bqt\proto --javalite_out=D:\bqt\out test.proto

同样,项目中应该添加 Java Lite 的源文件(或jar包)或直接添加 Java Lite 的依赖:
implementation 'com.google.protobuf:protobuf-lite:3.0.1'//protobuf lite
 
1
implementation 'com.google.protobuf:protobuf-lite:3.0.1'//protobuf lite
这里的版本号要比使用的 protoc插件 版本相同或更高(文档中说只要大于3.0.0就可以)。

----------------------------以下内容我还没去研究-----------------------------
Use Protobuf Java Lite Runtime with Bazel:
Bazel has native build rules to work with protobuf。对于Java Lite运行时,您可以使用java_lite_proto_library规则。 查看我们的构建文件示例以了解如何使用它。
----------------------------以上内容我还没去研究-----------------------------

2018-8-17

猜你喜欢

转载自www.cnblogs.com/baiqiantao/p/9497894.html