从零开始的RPC(五):Protobuf消息类型(三)
Protobuf类型 (三)
定义服务 (Defining Services)
If you want to use your message types with an RPC (Remote Procedure Call) system, you can define an RPC service interface in a
.protofile and the protocol buffer compiler will generate service interface code and stubs in your chosen language. So, for example, if you want to define an RPC service with a method that takes yourSearchRequestand returns aSearchResponse, you can define it in your.protofile as follows:
service SearchService {
rpc Search(SearchRequest) returns (SearchResponse);
}The most straightforward RPC system to use with protocol buffers is gRPC: a language- and platform-neutral open source RPC system developed at Google. gRPC works particularly well with protocol buffers and lets you generate the relevant RPC code directly from your
.protofiles using a special protocol buffer compiler plugin.
If you don’t want to use gRPC, it’s also possible to use protocol buffers with your own RPC implementation. You can find out more about this in the Proto2 Language Guide.
There are also a number of ongoing third-party projects to develop RPC implementations for Protocol Buffers. For a list of links to projects we know about, see the third-party add-ons wiki page.
JSON映射 (JSON Mapping)
The standard protobuf binary wire format is the preferred serialization format for communication between two systems that use protobufs. For communicating with systems that use JSON rather than protobuf wire format, Protobuf supports a canonical encoding in JSON.
可选option配置 (Options)
Individual declarations in a
.protofile can be annotated with a number of options. Options do not change the overall meaning of a declaration, but may affect the way it is handled in a particular context. The complete list of available options is defined in/google/protobuf/descriptor.proto.
Some options are file-level options, meaning they should be written at the top-level scope, not inside any message, enum, or service definition. Some options are message-level options, meaning they should be written inside message definitions. Some options are field-level options, meaning they should be written inside field definitions. Options can also be written on enum types, enum values, oneof fields, service types, and service methods; however, no useful options currently exist for any of these.
Here are a few of the most commonly used options:
java_package(file option)java_outer_classname(file option)java_multiple_files(file option)optimize_for(file option):只影响C++和Java的代码生成行为cc_generic_services,java_generic_services,py_generic_services(file options):泛型服务已被废弃cc_enable_arenas(file option):在生成的C++代码中启用一次性分配一次性释放的内存分配方式objc_class_prefix(file option):Ojective C的packed(field option):默认对列表和基本数值类型为truedeprecated(field option): If set totrue, indicates that the field is deprecated and should not be used by new code. In most languages this has no actual effect. In Java, this becomes a@Deprecatedannotation. For C++, clang-tidy will generate warnings whenever deprecated fields are used. In the future, other language-specific code generators may generate deprecation annotations on the field’s accessors, which will in turn cause a warning to be emitted when compiling code which attempts to use the field. If the field is not used by anyone and you want to prevent new users from using it, consider replacing the field declaration with a reserved statement.
int32 old_field = 6 [deprecated = true];枚举值配置项 (Enum Value Options)
Enum value options are supported. You can use the
deprecatedoption to indicate that a value shouldn’t be used anymore. You can also create custom options using extensions.
import "google/protobuf/descriptor.proto";
extend google.protobuf.EnumValueOptions {
optional string string_name = 123456789;
}
enum Data {
DATA_UNSPECIFIED = 0;
DATA_SEARCH = 1 [deprecated = true];
DATA_DISPLAY = 2 [
(string_name) = "display_value"
];
}The C++ code to read the
string_nameoption might look something like this:
const absl::string_view foo = proto2::GetEnumDescriptor<Data>()
->FindValueByName("DATA_DISPLAY")->options().GetExtension(string_name);See Custom Options to see how to apply custom options to enum values and to fields.
自定义配置项 (Custom Options)
Protocol Buffers also allows you to define and use your own options. Note that this is an advanced feature which most people don’t need. If you do think you need to create your own options, see the Proto2 Language Guide for details. Note that creating custom options uses extensions, which are permitted only for custom options in proto3.
配置维持 (Option Retention)
编译.proto
To generate the Java, Kotlin, Python, C++, Go, Ruby, Objective-C, or C# code that you need to work with the message types defined in a .proto file, you need to run the protocol buffer compiler protoc on the .proto file. If you haven’t installed the compiler, download the package and follow the instructions in the README. For Go, you also need to install a special code generator plugin for the compiler; you can find this and installation instructions in the golang/protobuf repository on GitHub.
The protobuf compiler is invoked as follows:
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.protoIMPORT_PATHspecifies a directory in which to look for.protofiles when resolvingimportdirectives. If omitted, the current directory is used. Multiple import directories can be specified by passing the--proto_pathoption multiple times.-I=_IMPORT_PATH_can be used as a short form of--proto_path.
Note: File paths relative to their proto_path must be globally unique in a given binary. For example, if you have proto/lib1/data.proto and proto/lib2/data.proto, those two files cannot be used together with -I=proto/lib1 -I=proto/lib2 because it would be ambiguous which file import "data.proto" will mean. Instead -Iproto/ should be used and the global names will be lib1/data.proto and lib2/data.proto.
If you are publishing a library and other users may use your messages directly, you should include a unique library name in the path that they are expected to be used under to avoid file name collisions. If you have multiple directories in one project, it is best practice to prefer setting one -I to a top level directory of the project.
You can provide one or more output directives:
--cpp_outgenerates C++ code inDST_DIR. See the C++ generated code reference for more.--java_outgenerates Java code inDST_DIR. See the Java generated code reference for more.--kotlin_outgenerates additional Kotlin code inDST_DIR. See the Kotlin generated code reference for more.--python_outgenerates Python code inDST_DIR. See the Python generated code reference for more.--go_outgenerates Go code inDST_DIR. See the Go generated code reference for more.--ruby_outgenerates Ruby code inDST_DIR. See the Ruby generated code reference for more.--objc_outgenerates Objective-C code inDST_DIR. See the Objective-C generated code reference for more.--csharp_outgenerates C# code inDST_DIR. See the C# generated code reference for more.--php_outgenerates PHP code inDST_DIR. See the PHP generated code reference for more.
As an extra convenience, if the
DST_DIRends in.zipor.jar, the compiler will write the output to a single ZIP-format archive file with the given name..jaroutputs will also be given a manifest file as required by the Java JAR specification. Note that if the output archive already exists, it will be overwritten.You must provide one or more
.protofiles as input. Multiple.protofiles can be specified at once. Although the files are named relative to the current directory, each file must reside in one of theIMPORT_PATHs so that the compiler can determine its canonical name.