Spring Boot with gRPC[RU]
После долгих поисков изящной и лаконичной реализации gRPC c Spring Boot и Gradle, прочтения документации, а также прибегая к помощи Stack Overflow (куда же без него) я все таки решился написать статью(english). Здесь я хотел бы описать только процесс создания сервера и клиента, не прибегая к теории и не объясняя что такое gRPC.
Чтобы перейти непосредственно к выполнению поставленной задачи вы должны иметь минимальные навыки работы со Spring Boot. Если читаете эту статью, вероятно, вы уже знакомы с вышеупомянутыми технологиями.
1. Сервер
1.1. Добавление зависимостей.
Для начала создадим Spring Boot проект и добавим в файл build.gradle плагин и одну зависимость.
Плагин:
id 'com.google.protobuf' version '0.8.19'
Зависимость:
implementation 'net.devh:grpc-server-spring-boot-starter:2.13.1.RELEASE'
Вот так будет выглядеть конечный файл build.gradle:
plugins {
id 'org.springframework.boot' version '2.7.4'
id 'io.spring.dependency-management' version '1.0.14.RELEASE'
id 'java'
id 'idea'
// protobuf plugin
id 'com.google.protobuf' version '0.8.19'
}
group = 'com.example'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '8'
repositories {
mavenCentral()
}
dependencies {
implementation 'org.springframework.boot:spring-boot-starter'
// grpc server
implementation 'net.devh:grpc-server-spring-boot-starter:2.13.1.RELEASE'
}
Теперь создадим один вспомогательный файл grpc.gradle для конфигурации gRPC. Эту конфигурацию можно было бы написать в исходном build.gradle файле, но лучше не засорять его, а держать всё относящееся к gRPC отдельно.
Файл grpc.gradle:
protobuf {
protoc {
artifact = "com.google.protobuf:protoc:3.7.1"
}
plugins {
grpc {
artifact = "io.grpc:protoc-gen-grpc-java:1.19.0"
}
}
generateProtoTasks {
ofSourceSet('main').each { task ->
task.builtins {
java {
outputSubDir = 'proto_gen'
}
}
task.plugins {
grpc {
outputSubDir = 'proto_gen'
}
}
}
}
generatedFilesBaseDir = "$projectDir/src/"
}
task cleanProtoGen {
doFirst {
delete("$projectDir/src/main/proto_gen")
}
}
clean.dependsOn cleanProtoGen
На этом все, что связано с зависимостями.
1.2. Реализация.
Создадим test.proto файл по пути src/main/proto/test.proto:
Следующий шаг будет реализация метода test определенного в файле test.proto. Для этого создадим класс MyServiceImpl:
На этом создание сервера закончено, но еще одна конфигурация которую можно пропустить - это изменение порта сервера. По умолчанию порт сервера 9090, его можно установить в файле application.properties:
grpc.port=9090
1.3. Тестирование.
Чтобы проверить работоспособность нашего сервера можно воспользоваться Postman.
Создадим новый тип запроса gRPC Request:
Импортируем test.proto файл из проекта Choose a File => Next:
Пропишем адрес нашего сервера localhost:9090 и из выпадающего списка выберем удаленный метод(процедуру) test. Во вкладке message передадим наш запрос:
Во вкладке Response получим ответ от нашего сервера.
2. Клиент
2.1. Добавление зависимостей.
Процес добавления зависимостей в клиент идентичен серверу, но оличается только одной зависимостью. Создадим еще один Spring Boot проект и добавим в файл build.gradle плагин и одну зависимость.
Плагин:
id 'com.google.protobuf' version '0.8.19'
Зависимость:
implementation 'net.devh:grpc-client-spring-boot-starter:2.13.1.RELEASE'
Вот так будет выглядеть конечный файл build.gradle:
plugins {
id 'org.springframework.boot' version '2.7.4'
id 'io.spring.dependency-management' version '1.0.14.RELEASE'
id 'java'
id 'idea'
// protobuf plugin
id 'com.google.protobuf' version '0.8.19'
}
group = 'com.example'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '8'
repositories {
mavenCentral()
}
dependencies {
implementation 'org.springframework.boot:spring-boot-starter'
// grpc client
implementation 'net.devh:grpc-client-spring-boot-starter:2.13.1.RELEASE'
}
Теперь создадим один вспомогательный файл grpc.gradle для конфигурации gRPC.
Файл grpc.gradle:
protobuf {
protoc {
artifact = "com.google.protobuf:protoc:3.7.1"
}
plugins {
grpc {
artifact = "io.grpc:protoc-gen-grpc-java:1.19.0"
}
}
generateProtoTasks {
ofSourceSet('main').each { task ->
task.builtins {
java {
outputSubDir = 'proto_gen'
}
}
task.plugins {
grpc {
outputSubDir = 'proto_gen'
}
}
}
}
generatedFilesBaseDir = "$projectDir/src/"
}
task cleanProtoGen {
doFirst {
delete("$projectDir/src/main/proto_gen")
}
}
clean.dependsOn cleanProtoGen
На этом все, что связано с зависимостями.
2.2. Реализация.
Создадим test.proto файл по пути src/main/proto/test.proto:
Следующий шаг будет создание класса использующего метод test нашего сервиса GrpcTestService:
Последний шаг будет добавление адреса нашего сервера в файл application.yaml:
3. Тестирование
Чтобы проверить работу клиента с сервером, добавим вызов метода printResponse после запуска клиента. Для этой цели будем использовать ApplicationRunner:
Запустим оба приложения и в логах клиента можем наблюдать результат выполнения метода printResponse:
Заключение
В этой статье я постарался кратко описать процес создание сервера и клиента с миниматьным количеством кода и конфигурации. Надеюсь статья была полезной и вы сможете использовать ее в ваших проектах.
Ссылки репозиториев: