Это 19-й день моего участия в августовском испытании обновлений.Подробности о событии:Испытание августовского обновления
Введение
Protocol Buffer — это метод сериализации объектов, разработанный Google.Он имеет небольшой размер и высокую скорость передачи, и его очень любят все. Protobuf - это независимый от платформы и языка протокол.Через файл определения protobuf его можно легко преобразовать в реализацию на нескольких языках, что очень удобно.
Сегодня я познакомлю вас с базовым использованием protobuf и конкретными случаями его комбинирования с java.
Зачем использовать протобуф
Мы знаем, что данные передаются в двоичном виде при передаче по сети. Обычно мы используем байты для представления, а байт — это 8 бит. Если вы хотите передавать объекты по сети, вам обычно необходимо сериализовать объекты. Цель сериализации — to Он преобразуется в массив байтов и передается в сеть.Когда получатель получает массив байтов, он десериализует массив байтов и, наконец, преобразует его в объект в java.
Затем есть несколько способов сериализации объектов Java:
- Используйте собственную сериализацию объектов JDK, но у самой сериализации JDK есть некоторые проблемы, и этот метод сериализации подходит только для передачи между Java-программами.Если это не-java-программа, такая как PHP или GO, то сериализация больше не применима .
- Вы также можете настроить протокол сериализации, степень гибкости таким образом относительно высока, но недостаточно распространена, и она также сложнее достичь, очень неожиданные проблемы, которые могут возникнуть.
- Преобразование данных в XML или JSON для передачи. Преимущество XML и JSON заключается в том, что они оба имеют начальные символы, которые могут различать объекты, и весь объект можно прочитать, оценивая положение этих символов. Но будь то XML или JSON, недостатком является то, что преобразованные данные относительно велики. Он также потребляет больше ресурсов во время десериализации.
Поэтому нам нужен новый метод сериализации — protobuf — гибкое, эффективное и автоматизированное решение.
Написав файл определения структуры данных .proto, а затем вызвав компилятор protobuf, будет сгенерирован соответствующий класс, реализующий автоматическое кодирование и анализ данных protobuf в эффективном двоичном формате. Сгенерированный класс предоставляет методы получения и установки для полей данных в файле определения и предоставляет сведения об обработке для чтения и записи. Важно отметить, что protobuf является прямой совместимостью, а это означает, что старые двоичные файлы также могут быть прочитаны с использованием новейшего протокола.
Определить файл .proto
Файл .proto определяет объект сообщения, который вы будете сериализовать. Возьмем базовый файл student.proto, который определяет самые основные свойства объекта student.
Давайте сначала посмотрим на относительно простой файл .proto:
syntax = "proto3";
package com.flydean;
option java_multiple_files = true;
option java_package = "com.flydean.tutorial.protos";
option java_outer_classname = "StudentListProtos";
message Student {
optional string name = 1;
optional int32 id = 2;
optional string email = 3;
enum PhoneType {
MOBILE = 0;
HOME = 1;
}
message PhoneNumber {
optional string number = 1;
optional PhoneType type = 2;
}
repeated PhoneNumber phones = 4;
}
message StudentList {
repeated Student student = 1;
}
Первая строка определяет синтаксис: используется протокол protobuf, по умолчанию используется proto2, поскольку текущая версия протокола — proto3, поэтому здесь мы используем proto3 в качестве примера.
Затем мы определяем пакет, где он находится, который ссылается на пакет, который генерирует файл при компиляции. Это пространство имен.Хотя мы определим java_package позже, необходимо определить пакет, чтобы конфликтовать с протоколами на языках, отличных от Java.
Затем есть три варианта, специально используемые java-программами. java_multiple_files, java_package и java_outer_classname.
Среди них java_multiple_files относится к количеству java-файлов после компиляции.Если это правда, то будет java-объект и класс.Если это ложь, определенные java-объекты будут включены в один и тот же файл.
java_package указывает имя пакета Java, которое должны использовать сгенерированные классы. Если это не указано явно, будет использоваться ранее определенное значение пакета.
Параметр java_outer_classname определяет имя класса-оболочки, который будет представлять этот файл. Если для java_outer_classname не указано значение, оно будет сгенерировано путем преобразования имени файла в верхний регистр. Например, «student.proto» по умолчанию будет использовать «Student» в качестве имени класса-оболочки.
Следующая часть - это определение сообщения, для простых типов, которые вы можете использовать Bool, Int32, Float, Double и String, чтобы определить тип поля.
В приведенном выше примере мы также использовали сложные композитные свойства и вложенные типы. Класс Enum также определен.
Выше мы присвоили идентификатор каждому значению атрибута, этот идентификатор является уникальным «тегом», используемым в двоичном кодировании. Поскольку теги с номерами 1-15 в protobuf занимают меньше места в байтах, чем теги с номерами выше 16, в целях оптимизации теги 1-15 обычно используются для часто используемых или повторяющихся элементов, а теги 16 и более высокие теги используются для менее часто используемых. необязательные элементы.
Затем посмотрите на модификаторы поля, есть три модификатора: необязательные, повторяющиеся и обязательные.
необязательный означает, что поле является необязательным и может быть установлено или не установлено. Если оно не установлено, будет использоваться значение по умолчанию. Для простых типов мы можем настроить значение по умолчанию. Если нет, будет использоваться значение по умолчанию системы. По умолчанию. Для системных значений по умолчанию число равно 0, строка является пустой строкой, а логическое значение равно false.
Повторение означает, что поле может повторяться, и это повторение на самом деле является структурой массива.
required указывает, что поле является обязательным, если поле не имеет значения, то поле будет считаться неинициализированным, попытка создания неинициализированного сообщения вызовет исключение RuntimeException, а анализ неинициализированного сообщения вызовет исключение IOException.
Обратите внимание, что обязательное поле не поддерживается в ProtO3.
Скомпилируйте файл протокола
После определения файла proto вы можете использовать команду protoc для его компиляции.
protoc — это компилятор, предоставляемый protobuf.Как правило, его можно загрузить непосредственно из библиотеки релизов на github. Если вы не хотите загружать напрямую или нужная вам версия недоступна в официальной библиотеке, вы можете использовать исходный код для ее прямой компиляции.
Команды, используемые protoc, следующие:
protoc --experimental_allow_proto3_optional -I=SRC_DIR --java_out=DST_DIR $SRC_DIR/student.proto
Если вы компилируете proto3, вам нужно добавить опцию --experimental_allow_proto3_Optional.
Давайте запустим код выше. Вы обнаружите, что в пакете com.flydean.tutorial.protos сгенерировано 5 файлов. Они есть:
Student.java
StudentList.java
StudentListOrBuilder.java
StudentListProtos.java
StudentOrBuilder.java
Среди них StudentListOrBuilder и StudentOrBuilder — два интерфейса, а Student и StudentList — реализации этих двух классов.
Объясните сгенерированный файл
В файле proto мы в основном определяем два класса Student и StudentList, которые определяют внутренний класс Builder, возьмем в качестве примера Student, посмотрим на определения этих двух классов:
public final class Student extends
com.google.protobuf.GeneratedMessageV3 implements
StudentOrBuilder
public static final class Builder extends
com.google.protobuf.GeneratedMessageV3.Builder<Builder> implements
com.flydean.tutorial.protos.StudentOrBuilder
Видно, что интерфейсы, которые они реализуют, одинаковы, что указывает на то, что они могут обеспечивать одинаковую функциональность. По сути, Builder — это оболочка для сообщений, и все операции над Student могут выполняться Builder.
Для полей в Student класс Student имеет только методы получения для этих полей, в то время как Builder имеет методы получения и установки.
Для Student методы для полей:
// required string name = 1;
public boolean hasName();
public String getName();
// required int32 id = 2;
public boolean hasId();
public int getId();
// optional string email = 3;
public boolean hasEmail();
public String getEmail();
// repeated .tutorial.Person.PhoneNumber phones = 4;
public List<PhoneNumber> getPhonesList();
public int getPhonesCount();
public PhoneNumber getPhones(int index);
Для Builder у каждого свойства есть еще два метода:
// required string name = 1;
public boolean hasName();
public java.lang.String getName();
public Builder setName(String value);
public Builder clearName();
// required int32 id = 2;
public boolean hasId();
public int getId();
public Builder setId(int value);
public Builder clearId();
// optional string email = 3;
public boolean hasEmail();
public String getEmail();
public Builder setEmail(String value);
public Builder clearEmail();
// repeated .tutorial.Person.PhoneNumber phones = 4;
public List<PhoneNumber> getPhonesList();
public int getPhonesCount();
public PhoneNumber getPhones(int index);
public Builder setPhones(int index, PhoneNumber value);
public Builder addPhones(PhoneNumber value);
public Builder addAllPhones(Iterable<PhoneNumber> value);
public Builder clearPhones();
Два дополнительных метода — это методы set и clear. clear — очистить содержимое поля и вернуть его в исходное состояние.
Мы также определяем класс перечисления PhoneType:
public enum PhoneType
implements com.google.protobuf.ProtocolMessageEnum
Реализация этого класса мало чем отличается от обычного класса перечисления.
Строители и сообщения
Как показано в предыдущем разделе, класс, соответствующий Message, имеет только методы get и имеет методы, поэтому он неизменяем.После создания объекта сообщения его нельзя изменить. Чтобы создать сообщение, вы должны сначала создать построитель, установить любые поля, которые вы хотите установить, в значения по вашему выбору, а затем вызвать метод build() построителя.
Каждый раз, когда вызывается метод Builder, будет возвращен новый Builder.Конечно, возвращенный Builder такой же, как исходный Builder.Возврат Builder предназначен только для облегчения непрерывного написания кода.
Следующий код показывает, как создать экземпляр Student:
Student xiaoming =
Student.newBuilder()
.setId(1234)
.setName("小明")
.setEmail("flydean@163.com")
.addPhones(
Student.PhoneNumber.newBuilder()
.setNumber("010-1234567")
.setType(Student.PhoneType.HOME))
.build();
Некоторые общие методы предоставляются в студенте, такие как isinitialized (), чтобы проверить, установлены ли все необходимые поля. TOSTRING () преобразует объект в строку. Строитель, который использует его, также может позвонить четко () для очистки заданного состояния и MergeFrom (сообщение другое), чтобы объединить объекты.
Сериализация и десериализация
Сгенерированный объект предоставляет методы сериализации и десериализации, нам нужно вызывать их только при необходимости:
- byte[] toByteArray();: сериализует сообщение и возвращает массив байтов, содержащий необработанные байты.
- static Person parseFrom(byte[] data);: Разбирает сообщение из заданного массива байтов.
- void writeTo(OutputStream output);: сериализовать сообщение и записать его в OutputStream.
- static Person parseFrom(InputStream input);: Читает и анализирует сообщение из InputStream.
Используя описанный выше метод, удобно сериализовать и реверсировать последовательность.
Расширение протокола
После того, как мы определим прототип, если мы хотим изменить его позже, мы надеемся, что новый протокол совместим с историческими данными. Тогда нам нужно учесть следующие моменты:
- Идентификационный номер существующего поля изменить нельзя.
- Обязательные поля не могут быть добавлены или удалены.
- Необязательные или повторяющиеся поля могут быть удалены.
- Вы можете добавить новое необязательное поле или поле повтора, но вы должны использовать новый идентификационный номер.
Суммировать
Что ж, здесь представлено основное использование протокола buf В следующей статье мы более подробно расскажем о конкретном содержании протокола proto, так что следите за обновлениями.
Примеры этой статьи могут относиться к:learn-java-base-9-to-20
Эта статья была включена вWoohoo.Floyd Press.com/01-протокол…
Самая популярная интерпретация, самая глубокая галантерея, самые краткие уроки и множество трюков, о которых вы не знаете, ждут вас!
Добро пожаловать, чтобы обратить внимание на мой официальный аккаунт: «Программируйте эти вещи», разбирайтесь в технологиях, лучше поймите себя!