Inleiding tot Google Protocol Buffer

1. Overzicht

In dit artikel zullen we kijken naar de Google Protocol Buffer (protobuf) - een bekend taal-agnostisch binair gegevensformaat. We kunnen een bestand definiëren met een protocol en vervolgens kunnen we met dat protocol code genereren in talen als Java, C ++, C #, Go of Python.

Dit is een inleidend artikel over het formaat zelf; Als je wilt zien hoe je het formaat gebruikt met een Spring-webapplicatie, bekijk dan dit artikel.

2. Maven-afhankelijkheden definiëren

Om protocolbuffers te gebruiken is Java, we moeten een Maven-afhankelijkheid toevoegen aan een protobuf-java:

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

3. Een protocol definiëren

Laten we beginnen met een voorbeeld. We kunnen een heel eenvoudig protocol definiëren in een protobuf-indeling:

bericht Persoon {vereiste tekenreeksnaam = 1; }

Dit is een protocol van een eenvoudig bericht van Persoon type dat slechts één verplicht veld heeft - naam met een draad type.

Laten we eens kijken naar het meer complexe voorbeeld van het definiëren van een protocol. Laten we zeggen dat we persoonsgegevens moeten opslaan in een protobuf-indeling:

pakket protobuf;

pakket protobuf; optie java_package = "com.baeldung.protobuf"; option java_outer_classname = "AddressBookProtos"; bericht Persoon {vereiste tekenreeksnaam = 1; vereiste int32 id = 2; optionele string email = 3; herhaalde reeksnummers = 4; } bericht Adresboek {herhaalde persoon personen = 1; }

Ons protocol bestaat uit twee soorten gegevens: a Persoon en een Adresboek. Na het genereren van de code (hierover meer in de latere sectie), zullen die klassen de innerlijke klassen binnen het Adresboek Protos klasse.

Wanneer we een veld willen definiëren dat vereist is - wat betekent dat het maken van een object zonder een dergelijk veld een Uitzondering, we moeten een verplicht trefwoord.

Een veld maken met de optioneel trefwoord betekent dat dit veld niet hoeft te worden ingesteld. De herhaald trefwoord is een array-type met een variabele grootte.

Alle velden zijn geïndexeerd - het veld dat wordt aangeduid met nummer 1 wordt opgeslagen als een eerste veld in een binair bestand. Veld gemarkeerd met 2 wordt vervolgens opgeslagen, enzovoort. Dat geeft ons een betere controle over hoe velden in het geheugen worden ingedeeld.

4. Java-code genereren vanuit een Protobuf-bestand

Zodra we een bestand hebben gedefinieerd, kunnen we er code uit genereren.

Ten eerste moeten we protobuf op onze machine installeren. Zodra we dit hebben gedaan, kunnen we code genereren door een protoc opdracht:

protoc -I =. --java_out =. adresboek.proto

De protoc commando genereert Java-uitvoerbestand van onze adresboek.proto het dossier. De -IK optie specificeert een map waarin een proto bestand zich bevindt. De java-out specificeert een map waar de gegenereerde klasse zal worden gemaakt.

De gegenereerde klasse heeft setters, getters, constructeurs en builders voor onze gedefinieerde berichten. Het zal ook enkele gebruiksmethoden hebben om protobuf-bestanden op te slaan en ze te deserialiseren van binair formaat naar Java-klasse.

5. Een instantie van door Protobuf gedefinieerde berichten maken

We kunnen eenvoudig een gegenereerde code gebruiken om een ​​Java-instantie van een Persoon klasse:

String email = "[e-mail beveiligd]"; int id = nieuwe Random (). nextInt (); String name = "Michael Program"; Tekenreeksnummer = "01234567890"; AddressBookProtos.Person person = AddressBookProtos.Person.newBuilder () .setId (id) .setName (naam) .setEmail (e-mail) .addNumbers (nummer) .build (); assertEquals (person.getEmail (), e-mail); assertEquals (person.getId (), id); assertEquals (person.getName (), naam); assertEquals (person.getNumbers (0), nummer);

We kunnen een vloeiende bouwer maken door een newBuilder () methode op het gewenste berichttype. Na het instellen van alle verplichte velden kunnen we een bouwen() methode om een ​​instantie van een Persoon klasse.

6. Protobuf serialiseren en deserialiseren

Zodra we een instantie van onze Persoon class, willen we dat op schijf opslaan in een binair formaat dat compatibel is met een aangemaakt protocol. Laten we zeggen dat we een instantie van het Adresboek class en voeg een persoon toe aan dat object.

Vervolgens willen we dat bestand op schijf opslaan - er is een Schrijven aan() util-methode in automatisch gegenereerde code die we kunnen gebruiken:

AddressBookProtos.AddressBook addressBook = AddressBookProtos.AddressBook.newBuilder (). AddPeople (persoon) .build (); FileOutputStream fos = nieuwe FileOutputStream (filePath); addressBook.writeTo (fos);

Na het uitvoeren van die methode, wordt ons object geserialiseerd naar binair formaat en opgeslagen op schijf. Om die gegevens van een schijf te laden en ze terug te deserialiseren naar het Adresboek object kunnen we een mergeFrom () methode:

AddressBookProtos.AddressBook deserialized = AddressBookProtos.AddressBook.newBuilder () .mergeFrom (nieuwe FileInputStream (filePath)). Build (); assertEquals (deserialized.getPeople (0) .getEmail (), e-mail); assertEquals (deserialized.getPeople (0) .getId (), id); assertEquals (deserialized.getPeople (0) .getName (), naam); assertEquals (gedeserialiseerd.getPeople (0) .getNumbers (0), nummer);

7. Conclusie

In dit korte artikel hebben we een standaard geïntroduceerd voor het beschrijven en opslaan van gegevens in een binair formaat: Google Protocol Buffer.

We hebben een eenvoudig protocol gemaakt, een Java-instantie gemaakt die voldoet aan het gedefinieerde protocol. Vervolgens hebben we gezien hoe we objecten kunnen serialiseren en deserialiseren met behulp van protobuf.

De implementatie van al deze voorbeelden en codefragmenten is te vinden in het GitHub-project - dit is een Maven-project, dus het moet gemakkelijk te importeren en uit te voeren zijn zoals het is.