目录

​​十三、定义服务(Service)​​

​​十四、JSON 映射​​

​​十五、选项​​

​​自定义选项​​

​​十六、生成访问类​​


十三、定义服务(Service)

如果想要将消息类型用在RPC(远程方法调用)系统中,可以在.proto文件中定义一个RPC服务接口,protocol buffer编译器将会根据所选择的不同语言生成服务接口代码及存根。如,想要定义一个RPC服务并具有一个方法,该方法能够接收 SearchRequest并返回一个SearchResponse,此时可以在.proto文件中进行如下定义:

service SearchService {
rpc Search (SearchRequest) returns (SearchResponse);
}

最直观的使用protocol buffer的RPC系统是​​gRPC​​一个由谷歌开发的语言和平台中的开源的PRC系统,gRPC在使用protocl buffer时非常有效,如果使用特殊的protocol buffer插件可以直接为您从.proto文件中产生相关的RPC代码。

如果你不想使用gRPC,也可以使用protocol buffer用于自己的RPC实现,你可以从​​proto2语言指南中找到更多信息​

还有一些第三方开发的PRC实现使用Protocol Buffer。参考​​第三方插件wiki​​查看这些实现的列表。

 

十四、JSON 映射

Proto3 支持JSON的编码规范,使他更容易在不同系统之间共享数据,在下表中逐个描述类型。

如果JSON编码的数据丢失或者其本身就是​​null​​,这个数据会在解析成protocol buffer的时候被表示成默认值。如果一个字段在protocol buffer中表示为默认值,体会在转化成JSON的时候编码的时候忽略掉以节省空间。具体实现可以提供在JSON编码中可选的默认值。

proto3

JSON

JSON示例

注意

message

object

{“fBar”: v, “g”: null, …}

产生JSON对象,消息字段名可以被映射成lowerCamelCase形式,并且成为JSON对象键,null被接受并成为对应字段的默认值

enum

string

“FOO_BAR”

枚举值的名字在proto文件中被指定

map

object

{“k”: v, …}

所有的键都被转换成string

repeated V

array

[v, …]

null被视为空列表

bool

true, false

true, false

 

string

string

“Hello World!”

 

bytes

base64 string

“YWJjMTIzIT8kKiYoKSctPUB+”

 

int32, fixed32, uint32

number

1, -10, 0

JSON值会是一个十进制数,数值型或者string类型都会接受

int64, fixed64, uint64

string

“1”, “-10”

JSON值会是一个十进制数,数值型或者string类型都会接受

float, double

number

1.1, -10.0, 0, “NaN”, “Infinity”

JSON值会是一个数字或者一个指定的字符串如”NaN”,”infinity”或者”-Infinity”,数值型或者字符串都是可接受的,指数符号也可以接受

Any

object

{“@type”: “url”, “f”: v, … }

如果一个Any保留一个特上述的JSON映射,则它会转换成一个如下形式:​​{"@type": xxx, "value": yyy}​​​否则,该值会被转换成一个JSON对象,​​@type​​字段会被插入所指定的确定的值

Timestamp

string

“1972-01-01T10:00:20.021Z”

使用RFC 339,其中生成的输出将始终是Z-归一化啊的,并且使用0,3,6或者9位小数

Duration

string

“1.000340012s”, “1s”

生成的输出总是0,3,6或者9位小数,具体依赖于所需要的精度,接受所有可以转换为纳秒级的精度

Struct

object

{ … }

任意的JSON对象,见struct.proto

Wrapper types

various types

2, “2”, “foo”, true, “true”, null, 0, …

包装器在JSON中的表示方式类似于基本类型,但是允许nulll,并且在转换的过程中保留null

FieldMask

string

“f.fooBar,h”

见fieldmask.proto

ListValue

array

[foo, bar, …]

 

Value

value

 

任意JSON值

NullValue

null

 

JSON null

 

十五、选项

在定义.proto文件时能够标注一系列的options。Options并不改变整个文件声明的含义,但却能够影响特定环境下处理方式。完整的可用选项可以在google/protobuf/descriptor.proto找到。

一些选项是文件级别的,意味着它可以作用于最外范围,不包含在任何消息内部、enum或服务定义中。一些选项是消息级别的,意味着它可以用在消息定义的内部。当然有些选项可以作用在域、enum类型、enum值、服务类型及服务方法中。到目前为止,并没有一种有效的选项能作用于所有的类型。

如下就是一些常用的选择:

  • ​java_package​​ (文件选项) :这个选项表明生成java类所在的包。如果在.proto文件中没有明确的声明java_package,就采用默认的包名。当然了,默认方式产生的 java包名并不是最好的方式,按照应用名称倒序方式进行排序的。如果不需要产生java代码,则该选项将不起任何作用。如:
option java_package = "com.example.foo";

​java_outer_classname​​ (文件选项): 该选项表明想要生成Java类的名称。如果在.proto文件中没有明确的java_outer_classname定义,生成的class名称将会根据.proto文件的名称采用驼峰式的命名方式进行生成。如(foo_bar.proto生成的java类名为FooBar.java),如果不生成java代码,则该选项不起任何作用。如:

option java_outer_classname = "Ponycopter";

​optimize_for​​(文件选项):可以被设置为 SPEED, CODE_SIZE,或者LITE_RUNTIME。这些值将通过如下的方式影响C++及java代码的生成:

  • ​SPEED (default)​​: protocol buffer编译器将通过在消息类型上执行序列化、语法分析及其他通用的操作。这种代码是最优的。
  • ​CODE_SIZE​​: protocol buffer编译器将会产生最少量的类,通过共享或基于反射的代码来实现序列化、语法分析及各种其它操作。采用该方式产生的代码将比SPEED要少得多, 但是操作要相对慢些。当然实现的类及其对外的API与SPEED模式都是一样的。这种方式经常用在一些包含大量的.proto文件而且并不盲目追求速度的 应用中。
  • ​LITE_RUNTIME​​: protocol buffer编译器依赖于运行时核心类库来生成代码(即采用libprotobuf-lite 替代libprotobuf)。这种核心类库由于忽略了一 些描述符及反射,要比全类库小得多。这种模式经常在移动手机平台应用多一些。编译器采用该模式产生的方法实现与SPEED模式不相上下,产生的类通过实现 MessageLite接口,但它仅仅是Messager接口的一个子集。
option optimize_for = CODE_SIZE;
  • ​cc_enable_arenas​​​(文件选项):对于C++产生的代码启用​​arena allocation​
  • ​objc_class_prefix​​(文件选项):设置Objective-C类的前缀,添加到所有Objective-C从此.proto文件产生的类和枚举类型。没有默认值,所使用的前缀应该是苹果推荐的3-5个大写字符,注意2个字节的前缀是苹果所保留的。
  • ​deprecated​​​(字段选项):如果设置为​​true​​则表示该字段已经被废弃,并且不应该在新的代码中使用。在大多数语言中没有实际的意义。在java中,这回变成​​@Deprecated​​注释,在未来,其他语言的代码生成器也许会在字标识符中产生废弃注释,废弃注释会在编译器尝试使用该字段时发出警告。如果字段没有被使用你也不希望有新用户使用它,尝试使用保留语句替换字段声明。
int32 old_field = 6 [deprecated=true];

 

自定义选项

ProtocolBuffers允许自定义并使用选项。该功能应该属于一个高级特性,对于大部分人是用不到的。如果你的确希望创建自己的选项,请参看​​ Proto2 Language Guide​​。注意创建自定义选项使用了拓展,拓展只在proto3中可用。

 

十六、生成访问类

可以通过定义好的.proto文件来生成Java,Python,C++, Ruby, JavaNano, Objective-C,或者C# 代码,需要基于.proto文件运行protocol buffer编译器protoc。如果你没有安装编译器,下载​​安装包​​​并遵照README安装。对于Go,你还需要安装一个特殊的代码生成器插件。你可以通过GitHub上的​​protobuf库​​找到安装过程

通过如下方式调用protocol编译器:


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 --javanano_out=DST_DIR --objc_out=DST_DIR --csharp_out=DST_DIR path/to/file.proto


  • ​IMPORT_PATH​​​声明了一个.proto文件所在的解析import具体目录。如果忽略该值,则使用当前目录。如果有多个目录则可以多次调用​​--proto_path​​,它们将会顺序的被访问并执行导入。​​-I=IMPORT_PATH​​是​​--proto_path​​的简化形式。
  • 当然也可以提供一个或多个输出路径:
  • ​--cpp_out​​​ 在目标目录DST_DIR中产生C++代码,可以在​​C++代码生成参考​​中查看更多。
  • ​--java_out​​​ 在目标目录DST_DIR中产生Java代码,可以在 ​​Java代码生成参考​​中查看更多。
  • ​--python_out​​​ 在目标目录 DST_DIR 中产生Python代码,可以在​​Python代码生成参考​​中查看更多。
  • ​--go_out​​​ 在目标目录 DST_DIR 中产生Go代码,可以在​​GO代码生成参考​​中查看更多。
  • ​--ruby_out​​在目标目录 DST_DIR 中产生Go代码,参考正在制作中。
  • ​--javanano_out​​​在目标目录DST_DIR中生成JavaNano,JavaNano代码生成器有一系列的选项用于定制自定义生成器的输出:你可以通过生成器的​​README​​查找更多信息,JavaNano参考正在制作中。
  • ​--objc_out​​​在目标目录DST_DIR中产生Object代码,可以在​​Objective-C代码生成参考​​中查看更多。
  • ​--csharp_out​​​在目标目录DST_DIR中产生Object代码,可以在​​C#代码生成参考​​中查看更多。
  • ​--php_out​​​在目标目录DST_DIR中产生Object代码,可以在​​PHP代码生成参考​​中查看更多。

作为一个方便的拓展,如果DST_DIR以.zip或者.jar结尾,编译器会将输出写到一个ZIP格式文件或者符合JAR标准的.jar文件中。注意如果输出已经存在则会被覆盖,编译器还没有智能到可以追加文件。 - 你必须提议一个或多个.proto文件作为输入,多个.proto文件可以只指定一次。虽然文件路径是相对于当前目录的,每个文件必须位于其IMPORT_PATH下,以便每个文件可以确定其规范的名称。