Введение в буфер протокола Google

Введение в буфер протокола Google

1. обзор

В этой статье мы рассмотримGoogle Protocol Buffer (protobuf) - хорошо известный не зависящий от языка формат двоичных данных. Мы можем определить файл с протоколом, а затем, используя этот протокол, мы можем генерировать код на таких языках, как Java, C ++, C #, Go или Python.

Это вводная статья к самому формату; если вы хотите узнать, как использовать формат в веб-приложении Spring, взгляните наthis article.

2. Определение зависимостей Maven

Чтобы использовать буферы протоколов на Java, нам нужно добавить зависимость Maven кprotobuf-java:


    com.google.protobuf
    protobuf-java
    ${protobuf.version}



    3.2.0

3. Определение протокола

Давайте начнем с примера. Мы можем определить очень простой протокол в формате protobuf:

message Person {
    required string name = 1;
}

Это протокол простого сообщения типаPerson, в котором есть только одно обязательное поле - имя, имеющее типstring.

Давайте посмотрим на более сложный пример определения протокола. Допустим, нам нужно сохранить данные о человеке в формате protobuf:

пакет protobuf;

package protobuf;

option java_package = "com.example.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;
}

Наш протокол состоит из двух типов данных:Person иAddressBook.. После генерации кода (подробнее об этом в следующем разделе) эти классы будут внутренними классами внутриAddressBookProtos. класс.

Когда мы хотим определить обязательное поле - это означает, что создание объекта без такого поля вызоветException, нам нужно использовать ключевое словоrequired.

Создание поля с ключевым словомoptional означает, что это поле не нужно устанавливать. Ключевое словоrepeated - это тип массива переменного размера.

Все поля проиндексированы - поле, обозначенное цифрой 1, будет сохранено как первое поле в двоичном файле. Поле, помеченное 2, будет сохранено далее и так далее. Это дает нам лучший контроль над тем, как поля расположены в памяти.

4. Создание кода Java из файла Protobuf

Определив файл, мы можем сгенерировать из него код.

Во-первых, нам нужноinstall protobuf на нашей машине. Сделав это, мы можем сгенерировать код, выполнив командуprotoc:

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

Командаprotoc сгенерирует выходной файл Java из нашего файлаaddressbook.proto. Параметр-I указывает каталог, в котором находится файлproto. java-out указывает каталог, в котором будет создан сгенерированный класс. __

Сгенерированный класс будет иметь сеттеры, геттеры, конструкторы и конструкторы для наших определенных сообщений. Он также будет иметь несколько утилит для сохранения файлов protobuf и десериализации их из двоичного формата в класс Java.

5. Создание экземпляра сообщений, определенных в Protobuf

Мы можем легко использовать сгенерированный код для создания Java-экземпляра классаPerson:

String email = "[email protected]";
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);

Мы можем создать свободный конструктор, используя методnewBuilder() для желаемого типа сообщения. После настройки всех обязательных полей мы можем вызвать методbuild() для создания экземпляра классаPerson.

6. Сериализация и десериализация Protobuf

Создав экземпляр нашего классаPerson, мы хотим сохранить его на диске в двоичном формате, совместимом с созданным протоколом. Допустим, мы хотим создать экземпляр классаAddressBook и добавить к этому объекту одного человека.

Затем мы хотим сохранить этот файл на диск - в автоматически сгенерированном коде есть метод utilwriteTo(), который мы можем использовать:

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

После выполнения этого метода наш объект будет сериализован в двоичный формат и сохранен на диске. Чтобы загрузить эти данные с диска и десериализовать их обратно в объект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. Заключение

В этой быстрой статье мы представили стандарт описания и хранения данных в двоичном формате - Google Protocol Buffer.

Мы создали простой протокол, создали экземпляр Java, который соответствует определенному протоколу. Далее мы увидели, как сериализовать и десериализовать объекты, используя protobuf.

Реализация всех этих примеров и фрагментов кода можно найти вGitHub project - это проект Maven, поэтому его должно быть легко импортировать и запускать как есть.