Inleiding tot gRPC

1. Inleiding

gRPC is een open source RPC-framework met hoge prestaties dat oorspronkelijk is ontwikkeld door Google. Het helpt bij het elimineren van standaardcode en helpt bij het verbinden van polyglot-services in en tussen datacenters.

2. Overzicht

Het raamwerk is gebaseerd op een client-server-model van externe procedureaanroepen. Een clienttoepassing kan methoden op een servertoepassing rechtstreeks aanroepen alsof het een lokaal object is.

In dit artikel worden de volgende stappen gevolgd om een ​​typische client-servertoepassing te maken met gRPC:

  1. Definieer een service in een .proto het dossier
  2. Genereer server- en clientcode met behulp van de protocolbuffer-compiler
  3. Creëer de servertoepassing, implementeer de gegenereerde service-interfaces en spawning de gRPC-server
  4. Maak de clienttoepassing en voer RPC-oproepen uit met behulp van gegenereerde stubs

Laten we een simpele definiëren HalloService die begroetingen retourneert in ruil voor de voor- en achternaam.

3. Maven afhankelijkheden

Laten we de afhankelijkheden grpc-netty, grpc-protobuf en grpc-stub toevoegen:

 io.grpc grpc-netty 1.16.1 io.grpc grpc-protobuf 1.16.1 io.grpc grpc-stub 1.16.1 

4. Het definiëren van de service

We beginnen met het definiëren van een service, methoden specificeren die op afstand kunnen worden aangeroepen, samen met hun parameters en retourtypen.

Dit gebeurt in het .proto bestand met behulp van de protocolbuffers. Ze worden ook gebruikt om de structuur van de payload-berichten te beschrijven.

4.1. Basisconfiguraties

Laten we een HalloService.proto bestand voor onze steekproef HalloService. We beginnen met het toevoegen van enkele basisconfiguratiedetails:

syntax = "proto3"; optie java_multiple_files = true; pakket org.baeldung.grpc;

De eerste regel vertelt de compiler welke syntaxis in dit bestand wordt gebruikt. Standaard genereert de compiler alle Java-code in één Java-bestand. De tweede regel overschrijft deze instelling en alles wordt in individuele bestanden gegenereerd.

Ten slotte specificeren we het pakket dat we willen gebruiken voor onze gegenereerde Java-klassen.

4.2. De berichtstructuur definiëren

Vervolgens definiëren we het bericht:

bericht HelloRequest {string firstName = 1; string lastName = 2; }

Dit definieert de payload van het verzoek. Hier wordt elk attribuut dat in het bericht wordt opgenomen, samen met het type gedefinieerd.

Aan elk attribuut moet een uniek nummer worden toegewezen, ook wel de tag genoemd. Deze tag wordt door de protocolbuffer gebruikt om het attribuut weer te geven in plaats van de attribuutnaam te gebruiken.

Dus, in tegenstelling tot JSON, waar we de kenmerknaam zouden doorgeven Voornaam elke keer zou de protocolbuffer het nummer 1 gebruiken om te vertegenwoordigen Voornaam. De definitie van de payload van de respons is vergelijkbaar met de aanvraag.

Merk op dat we dezelfde tag kunnen gebruiken voor meerdere berichttypen:

bericht HelloResponse {string groet = 1; }

4.3. Het servicecontract definiëren

Laten we tot slot het servicecontract definiëren. Voor onze HalloService we definiëren een Hallo() operatie:

service HelloService {rpc hallo (HelloRequest) retourneert (HelloResponse); }

De Hallo() operatie accepteert een unair verzoek en retourneert een unair antwoord. gRPC ondersteunt ook streaming door voorvoegsels stroom trefwoord bij het verzoek en de reactie.

5. Genereren van de code

Nu passeren we de HalloService.proto bestand naar de protocolbuffer-compiler protoc om de Java-bestanden te genereren. Er zijn meerdere manieren om dit te activeren.

5.1. Met behulp van Protocol Buffer Compiler

Ten eerste hebben we de Protocol Buffer Compiler nodig. We kunnen kiezen uit vele voorgecompileerde binaire bestanden die hier beschikbaar zijn.

Bovendien hebben we de gRPC Java Codegen Plugin nodig.

Ten slotte kunnen we de volgende opdracht gebruiken om de code te genereren:

protoc --plugin = protoc-gen-grpc-java = $ PATH_TO_PLUGIN -I = $ SRC_DIR --java_out = $ DST_DIR --grpc-java_out = $ DST_DIR $ SRC_DIR / HelloService.proto

5.2. Maven-plug-in gebruiken

Als ontwikkelaar wilt u dat de codegeneratie nauw wordt geïntegreerd met uw build-systeem. gRPC biedt een protobuf-maven-plugin voor het Maven-buildsysteem:

   kr.motd.maven os-maven-plugin 1.6.1 org.xolstice.maven.plugins protobuf-maven-plugin 0.6.1 com.google.protobuf: protoc: 3.3.0: exe: $ {os.detected.classifier} grpc-java io.grpc: protoc-gen-grpc-java: 1.4.0: exe: $ {os.detected.classifier} compileren compileren-aangepast 

De os-maven-plugin extensie / plugin genereert verschillende handige platformafhankelijke projecteigenschappen zoals $ {os.detected.classifier}

6. Creëren van de server

Ongeacht de methode die u gebruikt voor het genereren van code, worden de volgende sleutelbestanden gegenereerd:

  • HelloRequest.java - bevat de HalloRequest typedefinitie
  • HalloResponse.javadit bevat de HelleResponse typedefinitie
  • HelloServiceImplBase.javadit bevat de abstracte klasse HalloServiceImplBase die een implementatie biedt van alle bewerkingen die we in de service-interface hebben gedefinieerd

6.1. De servicebasisklasse overschrijven

De standaardimplementatie van de abstracte klasse HalloServiceImplBase is om een ​​runtime-uitzondering te genererenio.grpc.StatusRuntimeException zeggend dat de methode niet geïmplementeerd is.

We zullen deze klasse uitbreiden en de Hallo() methode genoemd in onze servicedefinitie:

openbare klasse HelloServiceImpl breidt HelloServiceImplBase uit {@Override public void hello (HelloRequest-verzoek, StreamObserver responseObserver) {String-groet = nieuwe StringBuilder () .append ("Hallo,") .append (request.getFirstName ()) .append (""). append (request.getLastName ()) .toString (); HelloResponse response = HelloResponse.newBuilder () .setGreeting (begroeting) .build (); responseObserver.onNext (antwoord); responseObserver.onCompleted (); }}

Als we de handtekening van Hallo() met degene die we schreven in de HellService.proto bestand, zullen we zien dat het niet terugkeert HalloResponse. In plaats daarvan neemt het het tweede argument als StreamObserver, wat een antwoordwaarnemer is, een terugroepactie voor de server om te bellen met zijn antwoord.

Op deze manier de klant krijgt een optie om een ​​blokkerende oproep te doen of een niet-blokkerende oproep.

gRPC gebruikt bouwers voor het maken van objecten. We gebruiken HelloResponse.newBuilder () en stel de begroetingstekst in om een HalloResponse voorwerp. We stellen dit object in op de responseObserver's onNext () methode om het naar de klant te sturen.

Ten slotte moeten we bellen onCompleted () om aan te geven dat we klaar zijn met het afhandelen van de RPC, anders wordt de verbinding verbroken en wacht de client tot er meer informatie binnenkomt.

6.2. De Grpc-server uitvoeren

Vervolgens moeten we de gRPC-server starten om te luisteren naar inkomende verzoeken:

openbare klasse GrpcServer {openbare statische leegte hoofd (String [] args) {Server server = ServerBuilder .forPort (8080) .addService (nieuwe HelloServiceImpl ()). build (); server.start (); server.awaitTermination (); }}

Hier gebruiken we opnieuw de builder om een ​​gRPC-server op poort 8080 te maken en de HelloServiceImpl service die we hebben gedefinieerd. begin() zou de server starten. In ons voorbeeld zullen we bellen wachtenTermination () om de server op de voorgrond te laten draaien door de prompt te blokkeren.

7. Creëren van de klant

gRPC biedt een kanaalconstructie die de onderliggende details abstraheert zoals verbinding, pooling van verbindingen, taakverdeling, enz.

We maken een kanaal met ManagedChannelBuilder. Hier specificeren we het serveradres en de poort.

We gebruiken platte tekst zonder enige codering:

openbare klasse GrpcClient {openbare statische leegte hoofd (String [] args) {ManagedChannel kanaal = ManagedChannelBuilder.forAddress ("localhost", 8080) .usePlaintext () .build (); HelloServiceGrpc.HelloServiceBlockingStub stub = HelloServiceGrpc.newBlockingStub (kanaal); HelloResponse helloResponse = stub.hello (HelloRequest.newBuilder () .setFirstName ("Baeldung") .setLastName ("gRPC") .build ()); channel.shutdown (); }}

Vervolgens moeten we een stub maken die we zullen gebruiken om de daadwerkelijke oproep op afstand te maken Hallo(). De stub is de belangrijkste manier voor clients om te communiceren met de server. Wanneer u automatisch gegenereerde stubs gebruikt, heeft de stub-klasse constructors voor het omhullen van het kanaal.

Hier gebruiken we een blokkerende / synchrone stub zodat de RPC-aanroep wacht tot de server reageert, en ofwel een antwoord retourneert of een uitzondering genereert. Er zijn twee andere soorten stubs die door gRPC worden geleverd, die niet-blokkerende / asynchrone oproepen mogelijk maken.

Eindelijk, tijd om de Hallo() RPC-oproep. Hier passeren we de HalloRequest. We kunnen de automatisch gegenereerde setters gebruiken om de Voornaam, achternaam attributen van de HalloRequest voorwerp.

We krijgen de HalloResponse object geretourneerd door de server.

8. Conclusie

In deze tutorial hebben we gezien hoe we gRPC konden gebruiken om de ontwikkeling van communicatie tussen twee services te vergemakkelijken door ons te concentreren op het definiëren van de service en de gRPC alle standaardcode te laten afhandelen.

Zoals gewoonlijk vind je de bronnen op GitHub.