Einführung in den Google Protocol Buffer

Einführung in Google Protocol Buffer

1. Überblick

In diesem Artikel beschäftigen wir uns mitGoogle Protocol Buffer (protobuf) - einem bekannten sprachunabhängigen Binärdatenformat. Wir können eine Datei mit einem Protokoll definieren und dann mit diesem Protokoll Code in Sprachen wie Java, C ++, C #, Go oder Python generieren.

Dies ist ein Einführungsartikel zum Format selbst; Wenn Sie sehen möchten, wie das Format mit einer Spring-Webanwendung verwendet wird, sehen Sie sichthis article an.

2. Maven-Abhängigkeiten definieren

Um Protokollpuffer in Java zu verwenden, müssen wir einemprotobuf-java eine Maven-Abhängigkeit hinzufügen:


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



    3.2.0

3. Protokoll definieren

Beginnen wir mit einem Beispiel. Wir können ein sehr einfaches Protokoll in einem Protobuf-Format definieren:

message Person {
    required string name = 1;
}

Dies ist ein Protokoll einer einfachen Nachricht vom TypPersonmit nur einem erforderlichen Feld - Name mit dem Typstring.

Schauen wir uns das komplexere Beispiel für die Definition eines Protokolls an. Nehmen wir an, wir müssen Personendaten in einem Protobuf-Format speichern:

Paket 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;
}

Unser Protokoll besteht aus zwei Arten von Daten: aPerson undAddressBook. Nach dem Generieren des Codes (mehr dazu im späteren Abschnitt) sind diese Klassen die inneren Klassen innerhalb derAddressBookProtos Klasse.

Wenn wir ein Feld definieren möchten, das erforderlich ist - was bedeutet, dass das Erstellen eines Objekts ohne ein solches Feld einException verursacht, müssen wir einrequired-Schlüsselwort verwenden.

Wenn Sie ein Feld mit dem Schlüsselwortoptionalerstellen, muss dieses Feld nicht festgelegt werden. Das Schlüsselwortrepeated ist ein Array-Typ mit variabler Größe.

Alle Felder sind indiziert - das mit der Nummer 1 bezeichnete Feld wird als erstes Feld in einer Binärdatei gespeichert. Das mit 2 markierte Feld wird als nächstes gespeichert und so weiter. Das gibt uns eine bessere Kontrolle darüber, wie die Felder im Speicher angeordnet sind.

4. Generieren von Java-Code aus einer Protobuf-Datei

Sobald wir eine Datei definiert haben, können wir daraus Code generieren.

Erstens müssen wirinstall protobuf auf unserer Maschine. Sobald wir dies getan haben, können wir Code generieren, indem wir einenprotoc-Befehl ausführen:

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

Der Befehlprotoc generiert eine Java-Ausgabedatei aus unsereraddressbook.proto-Datei. Die Option-I gibt ein Verzeichnis an, in dem sich eineproto-Datei befindet. java-out gibt ein Verzeichnis an, in dem die generierte Klasse erstellt wird. __

Die generierte Klasse enthält Setter, Getter, Konstruktoren und Builder für unsere definierten Nachrichten. Es wird auch einige nützliche Methoden zum Speichern und Deserialisieren von Protobuf-Dateien vom Binärformat in die Java-Klasse geben.

5. Erstellen einer Instanz von Protobuf-definierten Nachrichten

Wir können leicht einen generierten Code verwenden, um eine Java-Instanz einerPerson-Klasse zu erstellen:

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);

Wir können einen fließenden Builder erstellen, indem wir einenewBuilder()-Methode für den gewünschten Nachrichtentyp verwenden. Nachdem wir alle erforderlichen Felder eingerichtet haben, können wir einebuild()-Methode aufrufen, um eine Instanz einerPerson-Klasse zu erstellen.

6. Serialisierung und Deserialisierung von Protobuf

Sobald wir eine Instanz unsererPerson-Klasse erstellt haben, möchten wir diese auf einer CD in einem Binärformat speichern, das mit einem erstellten Protokoll kompatibel ist. Angenommen, wir möchten eine Instanz der KlasseAddressBookerstellen und diesem Objekt eine Person hinzufügen.

Als nächstes möchten wir diese Datei auf einer Disc speichern. Es gibt einewriteTo() util-Methode in automatisch generiertem Code, die wir verwenden können:

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

Nach dem Ausführen dieser Methode wird unser Objekt in ein Binärformat serialisiert und auf einer Disc gespeichert. Um diese Daten von einer Disc zu laden und wieder in das ObjektAddressBookzu deserialisieren, können Sie die MethodemergeFrom()verwenden:

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. Fazit

In diesem kurzen Artikel haben wir einen Standard zur Beschreibung und Speicherung von Daten in einem Binärformat eingeführt - den Google Protocol Buffer.

Wir haben ein einfaches Protokoll erstellt, eine Java-Instanz, die dem definierten Protokoll entspricht. Als nächstes haben wir gesehen, wie man Objekte mit protobuf serialisiert und deserialisiert.

Die Implementierung all dieser Beispiele und Codefragmente finden Sie inGitHub project - dies ist ein Maven-Projekt, daher sollte es einfach zu importieren und auszuführen sein, wie es ist.