1. Przegląd
gRPC to niezależna od języka i platformy struktura zdalnych wywołań procedur (RPC) oraz zestaw narzędzi opracowany w Google. Umożliwia zdefiniowanie usługi za pomocą buforów protokołu, czyli szczególnie zaawansowanego zestawu narzędzi i języka do serializacji binarnej. Umożliwia to generowanie idiomatycznych stubów klienta i serwera z definicji usługi w różnych językach.
W tym ćwiczeniu dowiesz się, jak utworzyć usługę opartą na Javie, która udostępnia interfejs API za pomocą platformy gRPC, a następnie napisać klienta, który będzie używać wygenerowanego stuba po stronie klienta gRPC.
Czego się nauczysz
- Język bufora protokołu
- Jak wdrożyć usługę gRPC za pomocą Javy
- Jak wdrożyć klienta gRPC w Javie
Jak zamierzasz korzystać z tego samouczka?
Jak oceniasz swoje doświadczenie w tworzeniu aplikacji Node.js?
Jak oceniasz tworzenie aplikacji w Go?
2. Konfiguracja i wymagania
Samodzielne konfigurowanie środowiska
- Zaloguj się w konsoli Google Cloud i utwórz nowy projekt lub użyj istniejącego. Jeśli nie masz jeszcze konta Gmail ani Google Workspace, musisz je utworzyć.



Zapamiętaj identyfikator projektu, czyli unikalną nazwę we wszystkich projektach Google Cloud (podana powyżej nazwa jest już zajęta i nie będzie działać w Twoim przypadku). W dalszej części tego laboratorium będzie on nazywany PROJECT_ID.
- Następnie musisz włączyć rozliczenia w konsoli Cloud, aby korzystać z zasobów Google Cloud.
Ukończenie tego laboratorium nie powinno wiązać się z dużymi kosztami, a nawet z żadnymi. Wykonaj instrukcje z sekcji „Czyszczenie”, w której znajdziesz informacje o tym, jak wyłączyć zasoby, aby uniknąć naliczenia opłat po zakończeniu tego samouczka. Nowi użytkownicy Google Cloud mogą skorzystać z bezpłatnego okresu próbnego, w którym mają do dyspozycji środki w wysokości 300 USD.
Google Cloud Shell
Ten moduł możesz wykonać na swoim komputerze, ale w tym przypadku będziemy używać Google Cloud Shell, czyli środowiska wiersza poleceń działającego w chmurze.
Ta maszyna wirtualna oparta na Debianie zawiera wszystkie potrzebne narzędzia dla programistów. Zawiera również stały katalog domowy o pojemności 5 GB i działa w Google Cloud, co znacznie zwiększa wydajność sieci i usprawnia proces uwierzytelniania. Oznacza to, że do ukończenia tego ćwiczenia potrzebujesz tylko przeglądarki (działa ona na Chromebooku).
- Aby aktywować Cloud Shell w konsoli Cloud, kliknij Aktywuj Cloud Shell
(udostępnienie środowiska i połączenie się z nim powinno zająć tylko kilka chwil).


Po połączeniu z Cloud Shell zobaczysz, że uwierzytelnianie zostało już przeprowadzone, a projekt jest już ustawiony na Twój identyfikator projektu PROJECT_ID.
gcloud auth list
Wynik polecenia
Credentialed accounts: - <myaccount>@<mydomain>.com (active)
gcloud config list project
Wynik polecenia
[core] project = <PROJECT_ID>
Jeśli z jakiegoś powodu projekt nie jest ustawiony, po prostu wydaj to polecenie:
gcloud config set project <PROJECT_ID>
Szukasz urządzenia PROJECT_ID? Sprawdź, jakiego identyfikatora użyto w krokach konfiguracji, lub wyszukaj go w panelu konsoli Cloud:

Cloud Shell domyślnie ustawia też niektóre zmienne środowiskowe, które mogą być przydatne podczas wykonywania kolejnych poleceń.
echo $GOOGLE_CLOUD_PROJECT
Wynik polecenia
<PROJECT_ID>
- Na koniec ustaw domyślną strefę i konfigurację projektu.
gcloud config set compute/zone us-central1-f
Możesz wybrać różne strefy. Więcej informacji znajdziesz w artykule Regiony i strefy.
3. Tworzenie usługi gRPC
Utwórz nowy projekt w Javie za pomocą Maven:
$ mvn archetype:generate -DgroupId=com.example.grpc \ -DartifactId=grpc-hello-server \ -DarchetypeArtifactId=maven-archetype-quickstart \ -DinteractiveMode=false $ cd grpc-hello-server
Dodawanie pliku definicji gRPC
W gRPC ładunki usług (żądania i odpowiedzi) oraz operacje usług muszą być rejestrowane w IDL (Interface Definition Language). gRPC używa składni Protobuffer 3 do definiowania ładunków wiadomości i operacji. Utwórzmy plik proto dla prostej usługi Greeting Service z żądaniem Hello Request i odpowiedzią Hello Response.
Najpierw utwórz nowy katalog proto, w którym będzie przechowywany nowy plik proto:
$ mkdir -p src/main/proto
Następnie utwórz nowy plik proto src/main/proto/GreetingService.proto.
Aby edytować plik, możesz użyć vim,nano,lub emacs:
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);
}
Dodawanie zależności i wtyczki gRPC
Gdy będziesz mieć definicję, możemy wygenerować z tego pliku zarówno stub po stronie serwera, jak i stub po stronie klienta. Musisz dodać zależności i wtyczki gRPC.
Najpierw dodaj zależności gRPC do pliku 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>
Następnie dodaj wtyczkę:
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>
Generowanie stubów
Podczas kompilowania aplikacji wtyczka przekonwertuje definicje proto na kod Java.
$ mvn -DskipTests package
Aby zobaczyć wygenerowane pliki:
$ find target/generated-sources
Wdrażanie Usługi
Najpierw utwórz nową klasę GreetingServiceImpl, która będzie implementować operację 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();
}
}
Implementowanie serwera
Na koniec musisz uruchomić serwer, aby nasłuchiwał na porcie i zarejestrować tę implementację usługi. Edytuj klasę App i jej główną metodę:
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();
}
}
Na koniec uruchom serwer:
$ mvn -DskipTests package exec:java -Dexec.mainClass=com.example.grpc.App ... Server Started
4. Korzystanie z usługi
Generator wygenerował już wszystkie stuby po stronie klienta. Aby uprościć to ćwiczenie, użyjemy tego samego projektu Maven, ale dodamy nową klasę Client z nową metodą główną.
Najpierw kliknij +, aby otworzyć nową sesję Cloud Shell, dzięki czemu nie musisz zamykać serwera:

W nowej sesji przejdź do katalogu grpc-hello-server:
$ cd grpc-hello-server
Następnie dodaj nową klasę 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();
}
}
Na koniec uruchom klienta:
$ mvn -DskipTests package exec:java -Dexec.mainClass=com.example.grpc.Client ... greeting: "Hello there, Ray"
To wszystko. Proste, prawda?
5. Usługa strumieniowania
Możesz wypróbować wiele innych rozwiązań. Możesz na przykład łatwo utworzyć usługę przesyłania strumieniowego, dodając słowo kluczowe stream w pliku proto do parametru żądania lub odpowiedzi, np.
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);
}
Zaktualizuj serwer, aby wysyłał wiele odpowiedzi, a nie tylko jedną. Możesz to zrobić, wykonując kilka wywoł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();
}
}
Klient musi używać stuba asynchronicznego zamiast stuba blokującego. Zaktualizuj kod klienta, pamiętając o zmianie typu stub na 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();
}
});
}
}
Przebuduj aplikację:
$ mvn -DskipTests package
Uruchom ponownie serwer i klienta w osobnych sesjach Cloud Shell.
Aby uruchomić serwer:
$ mvn exec:java -Dexec.mainClass=com.example.grpc.App ... Server Started
Aby uruchomić klienta:
$ mvn exec:java -Dexec.mainClass=com.example.grpc.Client ... greeting: "Hello there, Ray" greeting: "Hello there, Ray" greeting: "Hello there, Ray"
6. Gratulacje!
Omówione zagadnienia:
- Język bufora protokołu
- Jak wdrożyć serwer gRPC w Javie
- Jak wdrożyć klienta gRPC w Javie
Dalsze kroki:
- Więcej informacji o gRPC Java
- Więcej przykładów gRPC w Javie znajdziesz na GitHubie
- Dowiedz się więcej o strumieniowaniu w gRPC
- Więcej informacji o transkodowaniu z gRPC na REST
Prześlij nam swoją opinię
- Poświęć chwilę na wypełnienie naszej krótkiej ankiety.