Introdução ao gRPC
Esta página explica como começar a usar o gRPC na sua aplicação Quarkus. Embora esta página descreva como configurá-lo com o Maven, também é possível usar o Gradle.
Vamos imaginar que o você tenha um projeto Quarkus normal, gerado a partir do gerador de projetos Quarkus . A configuração padrão é suficiente, mas você também pode selecionar algumas extensões, se desejar.
Solução
Recomendamos que siga as instruções nas seções seguintes e crie a aplicação passo a passo. No entanto, você pode ir diretamente para o exemplo completo.
Clone o repositório Git: git clone https://github.com/quarkusio/quarkus-quickstarts.git, ou baixe um arquivo.
The solution is located in the grpc-plain-text-quickstart directory.
Configurando seu projeto
Edit the pom.xml file to add the Quarkus gRPC extension dependency (just under <dependencies>):
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-grpc</artifactId>
</dependency>
Por padrão, a extensão quarkus-grpc se baseia no modelo de programação reativa. Neste guia, seguiremos uma abordagem reativa. Na seção dependencies do seu arquivo pom.xml, certifique-se de ter a dependência RESTEasy Reactive:
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-resteasy-reactive</artifactId>
</dependency>
Make sure you have generate-code goal of quarkus-maven-plugin enabled in your pom.xml.
If you wish to generate code from different proto files for tests, also add the generate-code-tests goal.
Please note that no additional task/goal is required for the Gradle plugin.
<build>
<plugins>
<plugin>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-maven-plugin</artifactId>
<version>${quarkus-plugin.version}</version>
<extensions>true</extensions>
<executions>
<execution>
<goals>
<goal>build</goal>
<goal>generate-code</goal>
<goal>generate-code-tests</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
Com essa configuração, você pode colocar as definições do seu serviço e mensagens no diretório src/main/proto.
O quarkus-maven-plugin irá gerar arquivos Java a partir dos seus arquivos proto.
O quarkus-maven-plugin recupera uma versão do protoc (o compilador protobuf) dos repositórios Maven. A versão recuperada corresponde ao seu sistema operacional e arquitetura de CPU. Se essa versão recuperada não funcionar no seu contexto, você pode forçar o uso de um classificador de sistema operacional diferente com -Dquarkus.grpc.protoc-os-classifier=seu-classificador-de-os (por exemplo, osx-x86_64). Você também pode baixar o binário adequado e especificar a localização via -Dquarkus.grpc.protoc-path=/caminho/para/protoc.
Alternatively to using the generate-code goal of the quarkus-maven-plugin, you can use protobuf-maven-plugin to generate these files, more in Generating Java files from proto with protobuf-maven-plugin
Vamos começar com um simples Hello service. Crie o arquivo src/main/proto/helloworld.proto com o seguinte conteúdo:
syntax = "proto3";
option java_multiple_files = true;
option java_package = "io.quarkus.example";
option java_outer_classname = "HelloWorldProto";
package helloworld;
// The greeting service definition.
service Greeter {
// Sends a greeting
rpc SayHello (HelloRequest) returns (HelloReply) {}
}
// The request message containing the user's name.
message HelloRequest {
string name = 1;
}
// The response message containing the greetings
message HelloReply {
string message = 1;
}
Este arquivo proto define uma interface de serviço simples com um único método ( SayHello), e as mensagens trocadas ( HelloRequest contendo o nome HelloReply e contendo a mensagem de saudação).
Antes de começar a programar, precisamos gerar as classes usadas para implementar e consumir os serviços gRPC. Em um terminal, execute:
$ mvn compile
Uma vez gerado, pode consultar o diretório target/generated-sources/grpc:
target/generated-sources/grpc
└── io
└── quarkus
└── example
├── Greeter.java
├── GreeterBean.java
├── GreeterClient.java
├── GreeterGrpc.java
├── HelloReply.java
├── HelloReplyOrBuilder.java
├── HelloRequest.java
├── HelloRequestOrBuilder.java
├── HelloWorldProto.java
└── MutinyGreeterGrpc.java
Estas são as classes que vamos utilizar.
proto files with imports
Protocol Buffers specification provides a way to import proto files.
The Quarkus code generation mechanism lets you control the scope of dependencies to scan for possible imports by setting the quarkus.generate-code.grpc.scan-for-imports property to one of the following:
-
all- scan all the dependencies -
none- don’t scan the dependencies, use only what is defined in thesrc/main/protoorsrc/test/proto -
groupId1:artifactId1,groupId2:artifactId2- scan only the dependencies with group id and artifact id in the list.
If not specified, the property is set to com.google.protobuf:protobuf-java.
To override it, set the quarkus.generate-code.grpc.scan-for-imports property in your application.properties to the desired value, e.g.
quarkus.generate-code.grpc.scan-for-imports=all
proto files from dependencies
In some cases, you may want to use proto files from a different project to generate the gRPC stubs. In this case:
-
Add a dependency on the artifact that contains the proto file to your project
-
In
application.properties, specify the dependencies you want to scan for proto files.
quarkus.generate-code.grpc.scan-for-proto=<groupId>:<artifactId>
The value of the property may be none, which is the default value, or a comma separated list of groupId:artifactId coordinates.
Diferentes implementações / tipos de gRPC
Outra coisa importante a se notar é que o suporte do Quarkus para gRPC atualmente inclui 3 diferentes tipos de uso do gRPC:
Documentações adicionais explicam como habilitar e usar cada um deles.
Implementação de um serviço gRPC
Agora que temos as classes geradas, vamos implementar o nosso serviço hello.
Com o Quarkus, implementar um serviço requer a implementação da interface de serviço gerada com base no Mutiny, uma API de Programação Reativa integrada no Quarkus, e expô-la como um bean CDI. Saiba mais sobre o Mutiny no [guia Mutiny](xref:mutiny-primer.adoc). A classe de serviço deve ser anotada com a anotação @io.quarkus.grpc.GrpcService.
Implementação de um serviço
Crie o arquivo src/main/java/org/acme/HelloService.java com o seguinte conteúdo:
package org.acme;
import io.quarkus.example.Greeter;
import io.quarkus.example.HelloReply;
import io.quarkus.example.HelloRequest;
import io.quarkus.grpc.GrpcService;
import io.smallrye.mutiny.Uni;
@GrpcService (1)
public class HelloService implements Greeter { (2)
@Override
public Uni<HelloReply> sayHello(HelloRequest request) { (3)
return Uni.createFrom().item(() ->
HelloReply.newBuilder().setMessage("Hello " + request.getName()).build()
);
}
}
| 1 | Exponha a sua implementação como um bean. |
| 2 | Implementar a interface de serviço gerada. |
| 3 | Implementar os métodos definidos na definição do serviço (neste caso, temos um único método). |
Você também pode usar a API gRPC padrão em vez do Mutiny:
package org.acme;
import io.grpc.stub.StreamObserver;
import io.quarkus.example.GreeterGrpc;
import io.quarkus.example.HelloReply;
import io.quarkus.example.HelloRequest;
import io.quarkus.grpc.GrpcService;
@GrpcService (1)
public class HelloService extends GreeterGrpc.GreeterImplBase { (2)
@Override
public void sayHello(HelloRequest request, StreamObserver<HelloReply> responseObserver) { (3)
String name = request.getName();
String message = "Hello " + name;
responseObserver.onNext(HelloReply.newBuilder().setMessage(message).build()); (4)
responseObserver.onCompleted(); (5)
}
}
| 1 | Exponha a sua implementação como um bean. |
| 2 | Estende a classe ImplBase. Esta é uma classe gerada. |
| 3 | Implementar os métodos definidos na definição do serviço (neste caso, temos um único método). |
| 4 | Construir e enviar a resposta. |
| 5 | Fechar a resposta. |
Se a lógica de implementação do seu serviço for bloqueante (usando E/S bloqueante, por exemplo), anote seu método com @Blocking. A anotação io.smallrye.common.annotation.Blocking instrui o framework a invocar o método anotado em uma thread de trabalho em vez da thread de E/S (event-loop).
|
O servidor gRPC
Os serviços são served by a server . Os serviços disponíveis (beans CDI ) são automaticamente registrados e expostos.
Por padrão, o servidor é exposto em localhost:9000 e utiliza texto simples (sem TLS) quando executado normalmente, e localhost:9001 para testes.
Executar a aplicação utilizando: mvn quarkus:dev.
Consumindo um serviço gRPC
Nesta seção, vamos consumir o serviço que expomos. Para simplificar, vamos consumir o serviço a partir da mesma aplicação, o que no mundo real não faz sentido.
Abra a classe org.acme.ExampleResource e edite o conteúdo para ficar:
package org.acme;
import io.quarkus.example.Greeter;
import io.quarkus.example.HelloRequest;
import io.quarkus.grpc.GrpcClient;
import io.smallrye.mutiny.Uni;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
@Path("/hello")
public class ExampleResource {
@GrpcClient (1)
Greeter hello; (2)
@GET
@Produces(MediaType.TEXT_PLAIN)
public String hello() {
return "hello";
}
@GET
@Path("/{name}")
public Uni<String> hello(String name) {
return hello.sayHello(HelloRequest.newBuilder().setName(name).build())
.onItem().transform(helloReply -> helloReply.getMessage()); (3)
}
}
| 1 | Injete o serviço e configure seu nome. O nome é utilizado na configuração da aplicação. Se não for especificado, é utilizado o nome do campo: hello neste caso específico. |
| 2 | Use a interface de serviço gerada com base na API Mutiny. |
| 3 | Invocar o serviço. |
Precisamos configurar a aplicação para indicar onde o serviço hello é encontrado. No arquivo src/main/resources/application.properties , adicione a seguinte propriedade:
quarkus.grpc.clients.hello.host=localhost
-
helloé o nome utilizado na anotação@GrpcClient. -
hostconfigura o host do serviço (aqui é localhost).
Em seguida, abra http://localhost:8080/hello/quarkus em um navegador e deverá receber Hello quarkus!
Empacotando a aplicação
Like any other Quarkus applications, you can package it with: mvn package.
You can also package the application into a native executable with: mvn package -Pnative.
Generating Java files from proto with protobuf-maven-plugin
Alternatively to using Quarkus code generation to generate stubs for proto files, you can also use
protobuf-maven-plugin.
To do it, first define the 2 following properties in the <properties> section:
<grpc.version>1.53.0</grpc.version>
<protoc.version>3.22.0</protoc.version>
They configure the gRPC version and the protoc version.
Then, add to the build section the os-maven-plugin extension and the protobuf-maven-plugin configuration.
<build>
<extensions>
<extension>
<groupId>kr.motd.maven</groupId>
<artifactId>os-maven-plugin</artifactId>
<version>${os-maven-plugin-version}</version>
</extension>
</extensions>
<plugins>
<plugin>
<groupId>org.xolstice.maven.plugins</groupId>
<artifactId>protobuf-maven-plugin</artifactId> (1)
<version>${protobuf-maven-plugin-version}</version>
<configuration>
<protocArtifact>com.google.protobuf:protoc:${protoc.version}:exe:${os.detected.classifier}</protocArtifact> (2)
<pluginId>grpc-java</pluginId>
<pluginArtifact>io.grpc:protoc-gen-grpc-java:${grpc.version}:exe:${os.detected.classifier}</pluginArtifact>
<protocPlugins>
<protocPlugin>
<id>quarkus-grpc-protoc-plugin</id>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-grpc-protoc-plugin</artifactId>
<version>2.16.12.Final</version>
<mainClass>io.quarkus.grpc.protoc.plugin.MutinyGrpcGenerator</mainClass>
</protocPlugin>
</protocPlugins>
</configuration>
<executions>
<execution>
<id>compile</id>
<goals>
<goal>compile</goal>
<goal>compile-custom</goal>
</goals>
</execution>
<execution>
<id>test-compile</id>
<goals>
<goal>test-compile</goal>
<goal>test-compile-custom</goal>
</goals>
</execution>
</executions>
</plugin>
<!-- ... -->
</plugins>
</build>
| 1 | The protobuf-maven-plugin that generates stub classes from your gRPC service definition (proto files). |
| 2 | The class generation uses a tool named protoc, which is OS-specific.
That’s why we use the os-maven-plugin to target the executable compatible with the operating system. |
This configuration instructs the protobuf-maven-plugin to generate the default gRPC classes and classes using Mutiny to fit with the Quarkus development experience.
|
When using protobuf-maven-plugin, instead of the quarkus-maven-plugin, every time you update the proto files, you need to re-generate the classes (using mvn compile).
|
gRPC classes from dependencies
When gRPC classes - the classes generated from proto files - are in a dependency of the application, then the dependency needs a Jandex index.
The jandex-maven-plugin can be used to create a Jandex index. More information on this topic can be found in the Bean Discovery section of the CDI guide.
<build>
<plugins>
<plugin>
<groupId>io.smallrye</groupId>
<artifactId>jandex-maven-plugin</artifactId>
<version>3.0.5</version>
<executions>
<execution>
<id>make-index</id>
<goals>
<goal>jandex</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>