目录

Protocol Buffers

Protocol Buffers(简称:ProtoBuf)是一种开源跨平台的序列化数据结构的协议。其对于存储资料或在网络上进行通信的程序是很有用的。这个方法包含一个接口描述语言,描述一些数据结构,并提供程序工具根据这些描述产生代码,这些代码将用来生成或解析代表这些数据结构的字节流。

proto3提供一个程序产生器,支持C++、Java (包含JavaNano)、Python、Go、Ruby、Objective-C和C#

非常适合任何需要以语言中立、平台中立、可扩展的方式序列化结构化、类似记录、类型化数据的情况。它们最常用于定义通信协议(与 gRPC 一起)和数据存储。

使用协议缓冲区的一些优点包括:

  • 紧凑的数据存储
  • 快速解析
  • 许多编程语言的可用性
  • 通过自动生成的类优化功能

Language Guide (proto3)

这个指南告诉你怎样用 protocol buffer language 结构化你的 protocol buffer data, 包括将 .proto 文件语法以及从 .proto 文件怎样生成数据访问类。

生成你的类

1
protoc --proto_path=IMPORT_PATH --cpp_out=DST_DIR --java_out=DST_DIR --python_out=DST_DIR --go_out=DST_DIR --ruby_out=DST_DIR --objc_out=DST_DIR --csharp_out=DST_DIR path/to/file.proto

.proto 文件 样式指南

标准文件格式

  • 保持行长为 80 个字符。
  • 使用 2 个空格的缩进。
  • 更喜欢对字符串使用双引号。

文件结构

文件应该命名 lower_snake_case.proto

所有文件应按以下方式排序:

  • 许可证标题(如果适用)
  • 文件概览
  • 句法
  • 包裹
  • 进口(排序)
  • 文件选项
  • 其他一切

包名应该是小写的。包名称应具有基于项目名称的唯一名称,并且可能基于包含协议缓冲区类型定义的文件的路径。

消息和字段名称

使用 CamelCase(首字母大写)作为消息名称 - 例如,SongServerRequest. 使用 underscore_separated_names 作为字段名称(包括 oneof 字段和扩展名)——例如,song_name.

1
2
3
message SongServerRequest {
  optional string song_name = 1;
}

对字段名称使用此命名约定可为您提供如下访问器:

1
2
  const string& song_name() { ... }
  void set_song_name(const string& x) { ... }
1
2
  public String getSongName() { ... }
  public Builder setSongName(String v) { ... }

如果您的字段名称包含数字,则该数字应出现在字母之后而不是下划线之后。例如,使用song_name1代替song_name_1

重复字段

对重复的字段使用复数名称。

1
2
3
  repeated string keys = 1;
  ...
  repeated MyMessage accounts = 17;

枚举

枚举类型名称使用 CamelCase(首字母大写),值名称使用 CAPITALS_WITH_UNDERSCORES:

1
2
3
4
5
enum FooBar {
  FOO_BAR_UNSPECIFIED = 0;
  FOO_BAR_FIRST_VALUE = 1;
  FOO_BAR_SECOND_VALUE = 2;
}

每个枚举值都应该以分号结尾,而不是逗号。更喜欢为枚举值添加前缀,而不是将它们包围在封闭的消息中。零值枚举应该有后缀UNSPECIFIED。

服务

如果您.proto定义了一个 RPC 服务,您应该使用 CamelCase(首字母大写)作为服务名称和任何 RPC 方法名称:

1
2
3
4
service FooService {
  rpc GetSomething(GetSomethingRequest) returns (GetSomethingResponse);
  rpc ListSomething(ListSomethingRequest) returns (ListSomethingResponse);
}

Tutorial Java

在 .proto 文件中定义消息格式

1
vim addressbook.proto
 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
syntax = "proto2";

package tutorial;

option java_multiple_files = true;
option java_package = "com.example.tutorial.protos";
option java_outer_classname = "AddressBookProtos";

message Person {
  optional string name = 1;
  optional int32 id = 2;
  optional string email = 3;

  enum PhoneType {
    MOBILE = 0;
    HOME = 1;
    WORK = 2;
  }

  message PhoneNumber {
    optional string number = 1;
    optional PhoneType type = 2 [default = HOME];
  }

  repeated PhoneNumber phones = 4;
}

message AddressBook {
  repeated Person people = 1;
}

使用 protocol buffer 编译器

如果您尚未安装编译器,请下载软件包并按照 README 中的说明进行操作。

1
protoc -I=$SRC_DIR --java_out=$DST_DIR $SRC_DIR/addressbook.proto

这com/example/tutorial/protos/会在您指定的目标目录中生成一个子目录,其中包含一些生成的.java文件。

使用 Java protocol buffer API 来写入和读取消息。

如果您查看com/example/tutorial/protos/,您会看到它包含.java为您在 中指定的每条消息定义一个类的文件addressbook.proto。每个类都有自己的Builder类,您可以使用它来创建该类的实例。

有关协议编译器为任何特定字段定义生成的确切成员的更多信息,请参阅Java 生成的代码参考

解析和序列化

最后,每个协议缓冲区类都有使用协议缓冲区二进制格式写入和读取您选择的类型的消息的方法。这些包括:

  • byte[] toByteArray();:序列化消息并返回包含其原始字节的字节数组。
  • static Person parseFrom(byte[] data);: 从给定的字节数组中解析消息。
  • void writeTo(OutputStream output);: 序列化消息并将其写入OutputStream.
  • static Person parseFrom(InputStream input);: 读取并解析来自InputStream.

protobuf-gradle-plugin

https://github.com/google/protobuf-gradle-plugin

 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
44
45
apply plugin: 'java'
apply plugin: 'com.google.protobuf'

buildscript {
  repositories {
    gradlePluginPortal()
  }
  dependencies {
    classpath 'com.google.protobuf:protobuf-gradle-plugin:0.8.19'
  }
}

sourceSets {
  main {
    proto {
      // In addition to the default 'src/main/proto'
      srcDir 'src/main/protobuf'
      srcDir 'src/main/protocolbuffers'
      // In addition to the default '**/*.proto' (use with caution).
      // Using an extension other than 'proto' is NOT recommended,
      // because when proto files are published along with class files, we can
      // only tell the type of a file from its extension.
      include '**/*.protodevel'
    }
    java {
      //...
    }
  }
  test {
    proto {
      // In addition to the default 'src/test/proto'
      srcDir 'src/test/protocolbuffers'
    }
  }
}

protobuf {
  generatedFilesBaseDir = "$projectDir/src/"
  // Configure the protoc executable
  protoc {
    // Download from repositories
    artifact = 'com.google.protobuf:protoc:3.0.0'
  }

}