Introduction to Google Protocol Buffer – 谷歌协议缓冲区简介

最后修改: 2017年 3月 15日

中文/混合/英文(键盘快捷键:t)

1. Overview

1.概述

In this article, we’ll be looking at the Google Protocol Buffer (protobuf) – a well-known language-agnostic binary data format. We can define a file with a protocol and next, using that protocol, we can generate code in languages like Java, C++, C#, Go, or Python.

在这篇文章中,我们将研究谷歌协议缓冲区(protobuf)–一种著名的语言无关的二进制数据格式。我们可以用协议定义一个文件,接下来,使用该协议,我们可以用Java、C++、C#、Go或Python等语言生成代码。

This is an introductory article to the format itself; if you want to see how to use the format with a Spring web application, have a look at this article.

这是一篇关于格式本身的介绍性文章;如果您想了解如何在Spring Web应用程序中使用该格式,请查看这篇文章

2. Defining Maven Dependencies

2.定义Maven的依赖性

To use protocol buffers is Java, we need to add a Maven dependency to a protobuf-java:

要使用协议缓冲区是Java,我们需要在protobuf-java中添加一个Maven依赖项。

<dependency>
    <groupId>com.google.protobuf</groupId>
    <artifactId>protobuf-java</artifactId>
    <version>${protobuf.version}</version>
</dependency>

<properties>
    <protobuf.version>3.2.0</protobuf.version>
</properties>

3. Defining a Protocol

3.定义一个协议

Let’s start with an example. We can define a very simple protocol in a protobuf format:

让我们从一个例子开始。我们可以用protobuf格式定义一个非常简单的协议。

message Person {
    required string name = 1;
}

This is a protocol of a simple message of Person type that has only one required field – name that has a string type.

这是一个Person类型的简单消息的协议,它只有一个必需的字段–具有string类型的name。

Let’s look at the more complex example of defining a protocol. Let’s say that we need to store person details in a protobuf format:

让我们看一下定义协议的更复杂的例子。比方说,我们需要以protobuf格式来存储个人的详细资料。

package protobuf;

包 protobuf。

package protobuf;

option java_package = "com.baeldung.protobuf";
option java_outer_classname = "AddressBookProtos";

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

    repeated string numbers = 4;
}

message AddressBook {
    repeated Person people = 1;
}

Our protocol consists of two types of data: a Person and an AddressBook. After generating the code (more on this in the later section), those classes will be the inner classes inside the AddressBookProtos class.

我们的协议包括两种类型的数据:一个Person 和一个AddressBook.在生成代码后(在后面的章节中会有更多介绍),这些类将成为AddressBookProtos 类中的内部类。

When we want to define a field that is required – meaning that creating an object without such field will cause an Exception, we need to use a required keyword.

当我们想定义一个必须的字段时–意味着创建一个没有这样的字段的对象将导致一个Exception,我们需要使用一个required关键字。

Creating a field with the optional keyword means that this field doesn’t need to be set. The repeated keyword is an array type of variable size.

optional关键字创建一个字段意味着这个字段不需要被设置。重复的关键字是一个大小可变的数组类型。

All fields are indexed – the field that is denoted with number 1 will be saved as a first field in a binary file. Field marked with 2 will be saved next and so on. That gives us better control over how fields are laid out in the memory.

所有字段都有索引–用数字1表示的字段将被保存为二进制文件中的第一个字段。标有2的字段将被接下来保存,以此类推。这使我们能够更好地控制字段在内存中的排列方式。

4. Generating Java Code From a Protobuf File

4.从Protobuf文件生成Java代码

Once we define a file, we can generate code from it.

一旦我们定义了一个文件,我们就可以从中生成代码。

Firstly, we need to install protobuf on our machine. Once we do this, we can generate code by executing a protoc command:

首先,我们需要在我们的机器上安装protobuf>。一旦我们做到这一点,我们就可以通过执行protoc命令来生成代码。

protoc -I=. --java_out=. addressbook.proto

The protoc command will generate Java output file from our addressbook.proto file. The -I option specifies a directory in which a proto file resides. The java-out specifies a directory where the generated class will be created.

protoc命令将从我们的addressbook.proto文件中生成Java输出文件 -I选项指定一个proto文件所在的目录。java-out指定了一个目录,生成的类将在这个目录中被创建。

Generated class will have setters, getters, constructors and builders for our defined messages. It will also have some util methods for saving protobuf files and deserializing them from binary format to Java class.

生成的类将有设置器、获取器、构造器和构建器用于我们定义的消息。它还会有一些用于保存protobuf文件和将它们从二进制格式反序列化为Java类的利用方法。

5. Creating an Instance of Protobuf Defined Messages

5.创建Protobuf定义的消息实例

We can easily use a generated code to create Java instance of a Person class:

我们可以轻松地使用生成的代码来创建Person 类的Java实例。

String email = "j@baeldung.com";
int id = new Random().nextInt();
String name = "Michael Program";
String number = "01234567890";
AddressBookProtos.Person person =
  AddressBookProtos.Person.newBuilder()
    .setId(id)
    .setName(name)
    .setEmail(email)
    .addNumbers(number)
    .build();

assertEquals(person.getEmail(), email);
assertEquals(person.getId(), id);
assertEquals(person.getName(), name);
assertEquals(person.getNumbers(0), number);

We can create a fluent builder by using a newBuilder() method on the desired message type. After setting up all required fields, we can call a build() method to create an instance of a Person class.

我们可以通过对所需的消息类型使用newBuilder() 方法来创建一个流畅的构建器。在设置了所有需要的字段后,我们可以调用build()方法来创建一个Person类的实例。

6. Serializing and Deserializing Protobuf

6.Protobuf的序列化和反序列化

Once we create an instance of our Person class, we want to save that on disc in a binary format that is compatible with a created protocol. Let’s say that we want to create an instance of the AddressBook class and add one person to that object.

一旦我们创建了Person 类的实例,我们就想把它以与创建的协议兼容的二进制格式保存在磁盘上。假设我们想创建一个AddressBook类的实例,并向该对象添加一个人。

Next, we want to save that file on disc – there is a writeTo() util method in auto-generated code that we can use:

接下来,我们要将该文件保存在磁盘上–在自动生成的代码中有一个writeTo()的利用方法,我们可以使用。

AddressBookProtos.AddressBook addressBook 
  = AddressBookProtos.AddressBook.newBuilder().addPeople(person).build();
FileOutputStream fos = new FileOutputStream(filePath);
addressBook.writeTo(fos);

After executing that method, our object will be serialized to binary format and saved on disc. To load that data from a disc and deserialize it back to the AddressBook object we can use a mergeFrom() method:

执行该方法后,我们的对象将被序列化为二进制格式并保存在磁盘上。为了从光盘中加载数据并将其反序列化回AddressBook 对象,我们可以使用mergeFrom() 方法。

AddressBookProtos.AddressBook deserialized
  = AddressBookProtos.AddressBook.newBuilder()
    .mergeFrom(new FileInputStream(filePath)).build();
 
assertEquals(deserialized.getPeople(0).getEmail(), email);
assertEquals(deserialized.getPeople(0).getId(), id);
assertEquals(deserialized.getPeople(0).getName(), name);
assertEquals(deserialized.getPeople(0).getNumbers(0), number);

7. Conclusion

7.结论

In this quick article, we introduced a standard for describing and storing data in a binary format – Google Protocol Buffer.

在这篇快速文章中,我们介绍了一种以二进制格式描述和存储数据的标准–谷歌协议缓冲区。

We created a simple protocol, created Java instance that complies with defined protocol. Next, we saw how to serialize and deserialize objects using protobuf.

我们创建了一个简单的协议,创建了符合定义的协议的Java实例。接下来,我们看到了如何使用protobuf对对象进行序列化和反序列化。

The implementation of all these examples and code snippets can be found in the GitHub project – this is a Maven project, so it should be easy to import and run as it is.

所有这些例子和代码片段的实现都可以在GitHub项目中找到–这是一个Maven项目,所以应该很容易导入并按原样运行。