1. Panoramica
gRPC è un framework e un set di strumenti per le chiamate di procedure remote (RPC) indipendenti dal linguaggio e dalla piattaforma sviluppati da Google. Consente di definire un servizio mediante buffer di protocollo, un set di strumenti e un linguaggio di serializzazione binaria particolarmente potente. Consente quindi di generare stub client e server idiomatici dalla definizione del tuo servizio in varie lingue.
In questo codelab, imparerai a creare un servizio basato su Java che espone un'API utilizzando il framework gRPC, quindi a scrivere un client per utilizzare lo stub lato client gRPC generato.
Cosa imparerai a fare
- Protocol Buffer Language (Linguaggio del buffer di protocollo)
- Come implementare un servizio gRPC utilizzando Java
- Come implementare un client gRPC utilizzando Java
Come utilizzerai questo tutorial?
Come valuteresti la tua esperienza con la creazione di app Node.js?
Come giudichi la tua esperienza con la creazione di app Go?
2. Configurazione e requisiti
Configurazione dell'ambiente da seguire in modo autonomo
- Accedi alla console Cloud e crea un nuovo progetto o riutilizzane uno esistente. Se non hai ancora un account Gmail o Google Workspace, devi crearne uno.
Ricorda l'ID progetto, un nome univoco in tutti i progetti Google Cloud (il nome precedente è già stato utilizzato e non funzionerà correttamente). Verrà indicato più avanti in questo codelab come PROJECT_ID
.
- Successivamente, dovrai abilitare la fatturazione in Cloud Console per utilizzare le risorse Google Cloud.
Eseguire questo codelab non dovrebbe costare molto. Assicurati di seguire le istruzioni nella sezione "Pulizia" in cui viene spiegato come arrestare le risorse in modo da non incorrere in fatturazione oltre questo tutorial. I nuovi utenti di Google Cloud sono idonei al programma prova senza costi di 300$.
Google Cloud Shell
Anche se questo codelab può essere gestito dal tuo computer, in questo codelab utilizzeremo Google Cloud Shell, un ambiente a riga di comando in esecuzione nel cloud.
Questa macchina virtuale basata su Debian viene caricata con tutti gli strumenti di sviluppo necessari. Offre una home directory permanente da 5 GB e viene eseguita in Google Cloud, migliorando notevolmente le prestazioni di rete e l'autenticazione. Ciò significa che per questo codelab è sufficiente un browser (sì, funziona su Chromebook).
- Per attivare Cloud Shell dalla console Cloud, fai semplicemente clic su Attiva Cloud Shell (il provisioning e la connessione all'ambiente dovrebbero richiedere solo pochi minuti).
Dopo la connessione a Cloud Shell, dovresti vedere che hai già eseguito l'autenticazione e che il progetto è già impostato su PROJECT_ID
.
gcloud auth list
Output comando
Credentialed accounts: - <myaccount>@<mydomain>.com (active)
gcloud config list project
Output comando
[core] project = <PROJECT_ID>
Se, per qualche motivo, il progetto non è impostato, invia semplicemente il seguente comando:
gcloud config set project <PROJECT_ID>
Stai cercando il tuo PROJECT_ID
? Controlla l'ID utilizzato nei passaggi di configurazione o cercalo nella dashboard della console Cloud:
Cloud Shell imposta anche alcune variabili di ambiente per impostazione predefinita, cosa che può essere utile quando eseguirai comandi futuri.
echo $GOOGLE_CLOUD_PROJECT
Output comando
<PROJECT_ID>
- Infine, imposta la zona e la configurazione del progetto predefinite.
gcloud config set compute/zone us-central1-f
Puoi scegliere zone diverse. Per ulteriori informazioni, consulta Regioni e Zone.
3. Crea un servizio gRPC
Crea un nuovo progetto Java con Maven:
$ mvn archetype:generate -DgroupId=com.example.grpc \ -DartifactId=grpc-hello-server \ -DarchetypeArtifactId=maven-archetype-quickstart \ -DinteractiveMode=false $ cd grpc-hello-server
Aggiungi un file di definizione gRPC
In gRPC, i payload dei servizi (richiesta e risposta) e le operazioni di servizio devono essere acquisiti in un IDL (Interface Definition Language). gRPC utilizza la sintassi Protobuffer 3 per definire i payload e le operazioni dei messaggi. Creiamo un file proto per un semplice servizio di benvenuto con una richiesta Hello e una risposta Hello.
Per prima cosa, crea una nuova directory proto in cui conservare il nuovo file proto:
$ mkdir -p src/main/proto
Quindi, crea un nuovo file di protocollo src/main/proto/GreetingService.proto
.
Puoi utilizzare vim,nano,
o emacs
per modificare il file:
src/main/proto/GreetingService.proto
syntax = "proto3"; package com.example.grpc; // Request payload message HelloRequest { // Each message attribute is strongly typed. // You also must assign a "tag" number. // Each tag number is unique within the message. string name = 1; // This defines a strongly typed list of String repeated string hobbies = 2; // There are many more basics types, like Enum, Map // See https://developers.google.com/protocol-buffers/docs/proto3 // for more information. } message HelloResponse { string greeting = 1; } // Defining a Service, a Service can have multiple RPC operations service GreetingService { // Define a RPC operation rpc greeting(HelloRequest) returns (HelloResponse); }
Aggiungi dipendenze gRPC e plug-in
Dopo aver ottenuto la definizione, da questo file possiamo generare sia lo stub lato server che lo stub lato client. Dovrai aggiungere le dipendenze e i plug-in gRPC.
Innanzitutto, aggiungi le dipendenze gRPC a pom.xml
:
pom.xml
<project> ... <dependencies> <dependency> <groupId>io.grpc</groupId> <artifactId>grpc-netty-shaded</artifactId> <version>1.24.0</version> </dependency> <dependency> <groupId>io.grpc</groupId> <artifactId>grpc-protobuf</artifactId> <version>1.24.0</version> </dependency> <dependency> <groupId>io.grpc</groupId> <artifactId>grpc-stub</artifactId> <version>1.24.0</version> </dependency> <dependency> <groupId>javax.annotation</groupId> <artifactId>javax.annotation-api</artifactId> <version>1.3.2</version> </dependency> ... </dependencies> ... </project>
Quindi, aggiungi il plug-in:
pom.xml
<project> ... <dependencies> ... </dependencies> <build> <extensions> <extension> <groupId>kr.motd.maven</groupId> <artifactId>os-maven-plugin</artifactId> <version>1.6.2</version> </extension> </extensions> <plugins> <plugin> <groupId>org.xolstice.maven.plugins</groupId> <artifactId>protobuf-maven-plugin</artifactId> <version>0.6.1</version> <configuration> <protocArtifact>com.google.protobuf:protoc:3.9.0:exe:${os.detected.classifier}</protocArtifact> <pluginId>grpc-java</pluginId> <pluginArtifact>io.grpc:protoc-gen-grpc-java:1.24.0:exe:${os.detected.classifier}</pluginArtifact> </configuration> <executions> <execution> <goals> <goal>compile</goal> <goal>compile-custom</goal> </goals> </execution> </executions> </plugin> </plugins> </build> </project>
Generare Stub
Quando crei l'applicazione, il plug-in converte le definizioni del protocollo in codice Java.
$ mvn -DskipTests package
Per visualizzare i file generati:
$ find target/generated-sources
Implementare il servizio
Innanzitutto, crea una nuova classe GreetingServiceImpl
che implementerà l'operazione greeting
:
src/main/java/com/example/grpc/GreetingServiceImpl.java
package com.example.grpc; import io.grpc.stub.StreamObserver; public class GreetingServiceImpl extends GreetingServiceGrpc.GreetingServiceImplBase { @Override public void greeting(GreetingServiceOuterClass.HelloRequest request, StreamObserver<GreetingServiceOuterClass.HelloResponse> responseObserver) { // HelloRequest has toString auto-generated. System.out.println(request); // You must use a builder to construct a new Protobuffer object GreetingServiceOuterClass.HelloResponse response = GreetingServiceOuterClass.HelloResponse.newBuilder() .setGreeting("Hello there, " + request.getName()) .build(); // Use responseObserver to send a single response back responseObserver.onNext(response); // When you are done, you must call onCompleted. responseObserver.onCompleted(); } }
Implementa il server
Infine, dovrai avviare un server per eseguire l'ascolto su una porta e registrare l'implementazione del servizio. Modifica la classe App
e il relativo metodo principale:
src/main/java/com/example/grpc/App.java
package com.example.grpc; import io.grpc.*; public class App { public static void main( String[] args ) throws Exception { // Create a new server to listen on port 8080 Server server = ServerBuilder.forPort(8080) .addService(new GreetingServiceImpl()) .build(); // Start the server server.start(); // Server threads are running in the background. System.out.println("Server started"); // Don't exit the main thread. Wait until server is terminated. server.awaitTermination(); } }
Infine, esegui il server:
$ mvn -DskipTests package exec:java -Dexec.mainClass=com.example.grpc.App ... Server Started
4. Utilizzo del servizio
Il generatore ha già generato tutti gli stub lato client. Per semplicità del lab, utilizzeremo lo stesso progetto Maven, ma semplicemente aggiungeremo una nuova classe Client
con un nuovo metodo principale.
Innanzitutto, fai clic su + per aprire una nuova sessione di Cloud Shell in modo da non dover terminare il server:
Nella nuova sessione, passa alla directory grpc-hello-server
:
$ cd grpc-hello-server
Quindi, aggiungi la nuova classe Client
:
src/main/java/com/example/grpc/Client.java
package com.example.grpc; import io.grpc.*; public class Client { public static void main( String[] args ) throws Exception { // Channel is the abstraction to connect to a service endpoint // Let's use plaintext communication because we don't have certs final ManagedChannel channel = ManagedChannelBuilder.forTarget("localhost:8080") .usePlaintext(true) .build(); // It is up to the client to determine whether to block the call // Here we create a blocking stub, but an async stub, // or an async stub with Future are always possible. GreetingServiceGrpc.GreetingServiceBlockingStub stub = GreetingServiceGrpc.newBlockingStub(channel); GreetingServiceOuterClass.HelloRequest request = GreetingServiceOuterClass.HelloRequest.newBuilder() .setName("Ray") .build(); // Finally, make the call using the stub GreetingServiceOuterClass.HelloResponse response = stub.greeting(request); System.out.println(response); // A Channel should be shutdown before stopping the process. channel.shutdownNow(); } }
Infine, esegui il client:
$ mvn -DskipTests package exec:java -Dexec.mainClass=com.example.grpc.Client ... greeting: "Hello there, Ray"
È tutto. È un gioco da ragazzi, no?
5. Servizio di streaming
Puoi provare molto di più. Ad esempio, puoi creare facilmente un servizio di streaming semplicemente aggiungendo la parola chiave stream
nel file proto al parametro di richiesta o di risposta, ad es.
src/main/proto/GreetingService.proto
syntax = "proto3"; package com.example.grpc; ... // Defining a Service, a Service can have multiple RPC operations service GreetingService { // MODIFY HERE: Update the return to streaming return. rpc greeting(HelloRequest) returns (stream HelloResponse); }
Aggiorna il server in modo che invii più risposte anziché una sola. Puoi farlo effettuando più chiamate a responseObserver.onNext(...)
:
src/main/java/com/example/grpc/GreetingServiceImpl.java
package com.example.grpc; import io.grpc.stub.StreamObserver; public class GreetingServiceImpl extends GreetingServiceGrpc.GreetingServiceImplBase { @Override public void greeting(GreetingServiceOuterClass.HelloRequest request, StreamObserver<GreetingServiceOuterClass.HelloResponse> responseObserver) { ... // Feel free to construct different responses if you'd like. responseObserver.onNext(response); responseObserver.onNext(response); responseObserver.onNext(response); // When you are done, you must call onCompleted. responseObserver.onCompleted(); } }
Il client deve utilizzare uno stub asincrono al posto dello stub di blocco. Aggiorna il codice client assicurandoti di aggiornare il tipo stub
in GreetingServiceStub
:
src/main/java/com/example/grpc/Client.java
package com.example.grpc; import io.grpc.*; // New import import io.grpc.stub.*; public class Client { public static void main( String[] args ) throws Exception { final ManagedChannel channel = ManagedChannelBuilder.forTarget("localhost:8080") .usePlaintext(true) .build(); // Replace the previous synchronous code with asynchronous code. // This time use an async stub: GreetingServiceGrpc.GreetingServiceStub stub = GreetingServiceGrpc.newStub(channel); // Construct a request GreetingServiceOuterClass.HelloRequest request = GreetingServiceOuterClass.HelloRequest.newBuilder() .setName("Ray") .build(); // Make an Asynchronous call. Listen to responses w/ StreamObserver stub.greeting(request, new StreamObserver<GreetingServiceOuterClass.HelloResponse>() { public void onNext(GreetingServiceOuterClass.HelloResponse response) { System.out.println(response); } public void onError(Throwable t) { } public void onCompleted() { // Typically you'll shutdown the channel somewhere else. // But for the purpose of the lab, we are only making a single // request. We'll shutdown as soon as this request is done. channel.shutdownNow(); } }); } }
Ricrea l'applicazione:
$ mvn -DskipTests package
Riavvia sia il server che il client, ciascuno nella propria sessione di Cloud Shell.
Per avviare il server:
$ mvn exec:java -Dexec.mainClass=com.example.grpc.App ... Server Started
Per avviare il client:
$ mvn exec:java -Dexec.mainClass=com.example.grpc.Client ... greeting: "Hello there, Ray" greeting: "Hello there, Ray" greeting: "Hello there, Ray"
6. Complimenti!
Argomenti trattati:
- Protocol Buffer Language (Linguaggio del buffer di protocollo)
- Come implementare un server gRPC utilizzando Java
- Come implementare un client gRPC utilizzando Java
Passaggi successivi:
- Scopri di più su gRPC Java
- Vedi altri esempi di Java gRPC su GitHub
- Scopri di più sullo flussi di dati in gRPC
- Scopri di più sulla transcodifica di gRPC a REST
Inviaci il tuo feedback
- Dedica qualche istante a completare il nostro breve sondaggio