1. Обзор
gRPC — это независимая от языка программирования и платформы платформа удаленного вызова процедур (RPC) и набор инструментов, разработанные в Google. Она позволяет определять сервис с помощью Protocol Buffers, особенно мощного набора инструментов и языка для бинарной сериализации. Затем она позволяет генерировать идиоматические клиентские и серверные заглушки из определения вашего сервиса на различных языках.
В этом практическом занятии вы научитесь создавать Java-сервис, предоставляющий API с использованием фреймворка gRPC, а затем писать клиент для использования сгенерированного клиентского заглушки gRPC.
Что вы узнаете
- Язык протокола буферизации
- Как реализовать gRPC-сервис с использованием Java
- Как реализовать gRPC-клиент с использованием Java
Как вы будете использовать этот учебник?
Как бы вы оценили свой опыт разработки приложений на Node.js?
Как бы вы оценили свой опыт разработки приложений на Go?
2. Настройка и требования
Настройка среды для самостоятельного обучения
- Войдите в Cloud Console и создайте новый проект или используйте существующий. Если у вас еще нет учетной записи Gmail или Google Workspace, вам необходимо ее создать .



Запомните идентификатор проекта (Project ID) — уникальное имя для всех проектов Google Cloud (указанное выше имя уже занято и вам не подойдёт, извините!). В дальнейшем в этом практическом занятии оно будет обозначаться как PROJECT_ID .
- Далее вам потребуется включить оплату в Cloud Console, чтобы использовать ресурсы Google Cloud.
Выполнение этого практического задания не должно стоить дорого, если вообще что-либо. Обязательно следуйте инструкциям в разделе «Очистка», где указано, как отключить ресурсы, чтобы избежать дополнительных расходов после завершения этого урока. Новые пользователи Google Cloud имеют право на бесплатную пробную версию стоимостью 300 долларов США .
Google Cloud Shell
Хотя эту практическую работу можно выполнить с вашего компьютера, в данном случае мы будем использовать Google Cloud Shell — среду командной строки, работающую в облаке.
Эта виртуальная машина на базе Debian содержит все необходимые инструменты разработки. Она предоставляет постоянный домашний каталог размером 5 ГБ и работает в облаке Google, что значительно повышает производительность сети и аутентификацию. Это означает, что для выполнения этого практического задания вам понадобится только браузер (да, он работает и на Chromebook).
- Для активации Cloud Shell из консоли Cloud Console просто нажмите «Активировать Cloud Shell».
(На подготовку и подключение к среде должно уйти всего несколько минут).


После подключения к Cloud Shell вы увидите, что ваша аутентификация пройдена и проект уже настроен на ваш PROJECT_ID .
gcloud auth list
вывод команды
Credentialed accounts: - <myaccount>@<mydomain>.com (active)
gcloud config list project
вывод команды
[core] project = <PROJECT_ID>
Если по какой-либо причине проект не создан, просто выполните следующую команду:
gcloud config set project <PROJECT_ID>
Ищете свой PROJECT_ID ? Проверьте, какой ID вы использовали на этапах настройки, или найдите его на панели управления Cloud Console:

Cloud Shell также по умолчанию устанавливает некоторые переменные среды, которые могут быть полезны при выполнении будущих команд.
echo $GOOGLE_CLOUD_PROJECT
вывод команды
<PROJECT_ID>
- Наконец, установите зону по умолчанию и конфигурацию проекта.
gcloud config set compute/zone us-central1-f
Вы можете выбрать различные зоны. Для получения дополнительной информации см. раздел «Регионы и зоны» .
3. Создайте службу gRPC.
Создайте новый Java-проект с помощью Maven:
$ mvn archetype:generate -DgroupId=com.example.grpc \ -DartifactId=grpc-hello-server \ -DarchetypeArtifactId=maven-archetype-quickstart \ -DinteractiveMode=false $ cd grpc-hello-server
Добавить файл определения gRPC
В gRPC полезная нагрузка сервиса (запрос и ответ) и операции сервиса должны быть описаны в IDL (языке определения интерфейса). gRPC использует синтаксис Protobuffer 3 для определения полезной нагрузки сообщений и операций. Давайте создадим proto-файл для простого сервиса приветствия с запросом Hello и ответом Hello.
Сначала создайте новую директорию proto для хранения нового файла proto:
$ mkdir -p src/main/proto
Затем создайте новый proto-файл src/main/proto/GreetingService.proto .
Для редактирования файла можно использовать vim,nano, или 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);
}
Добавьте зависимости gRPC и плагин.
После того, как у вас будет определение, мы сможем сгенерировать из этого файла как серверный, так и клиентский заглушки. Вам потребуется добавить зависимости и плагины gRPC.
Сначала добавьте зависимости gRPC в файл 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>
Затем добавьте плагин:
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>
Сгенерировать заглушки
При сборке приложения плагин преобразует определения протоколов в код Java.
$ mvn -DskipTests package
Чтобы посмотреть сгенерированные файлы:
$ find target/generated-sources
Внедрить сервис
Сначала создайте новый класс GreetingServiceImpl , который будет реализовывать операцию 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();
}
}
Реализация сервера
Наконец, вам потребуется запустить сервер для прослушивания порта и зарегистрировать реализацию этого сервиса. Отредактируйте класс App и его метод main:
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();
}
}
Наконец, запустите сервер:
$ mvn -DskipTests package exec:java -Dexec.mainClass=com.example.grpc.App ... Server Started
4. Использование услуги
Генератор уже сгенерировал все клиентские заглушки. Для упрощения лабораторной работы мы будем использовать тот же проект Maven, но просто добавим новый класс Client с новым методом main.
Сначала нажмите на кнопку «+» , чтобы открыть новую сессию Cloud Shell и не завершать работу сервера:

В новой сессии перейдите в каталог grpc-hello-server :
$ cd grpc-hello-server
Затем добавьте новый класс 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();
}
}
Наконец, запустите клиент:
$ mvn -DskipTests package exec:java -Dexec.mainClass=com.example.grpc.Client ... greeting: "Hello there, Ray"
Вот и всё! Довольно просто, правда?
5. Стриминговый сервис
Есть еще много чего, что вы можете попробовать. Например, вы можете легко создать потоковый сервис, просто добавив ключевое слово stream в proto-файл либо к параметру запроса, либо к параметру ответа, например.
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);
}
Обновите свой сервер, чтобы он отправлял несколько ответов вместо одного. Это можно сделать, выполнив несколько вызовов 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();
}
}
Клиент должен использовать асинхронный заглушечный модуль вместо блокирующего. Обновите код клиента, убедившись, что тип stub изменен на 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();
}
});
}
}
Пересоберите приложение:
$ mvn -DskipTests package
Перезапустите сервер и клиент, каждый в отдельной сессии Cloud Shell.
Для запуска сервера:
$ mvn exec:java -Dexec.mainClass=com.example.grpc.App ... Server Started
Для запуска клиента:
$ mvn exec:java -Dexec.mainClass=com.example.grpc.Client ... greeting: "Hello there, Ray" greeting: "Hello there, Ray" greeting: "Hello there, Ray"
6. Поздравляем!
Что мы рассмотрели:
- Язык протокола буферизации
- Как реализовать gRPC-сервер с использованием Java
- Как реализовать gRPC-клиент с использованием Java
Следующие шаги:
- Узнайте больше о gRPC на Java
- Больше примеров gRPC на Java смотрите на GitHub.
- Узнайте о потоковой передаче данных в gRPC.
- Узнайте больше о преобразовании gRPC в REST.
Оставьте свой отзыв.
- Пожалуйста, уделите несколько минут, чтобы пройти наш очень короткий опрос.