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 você siga as instruções nas próximas seções e crie a aplicação passo a passo. No entanto, você pode ir direto para o exemplo completo.
Clone o repositório Git: git clone https://github.com/quarkusio/quarkus-quickstarts.git
, ou baixe um arquivo.
A solução está localizada no diretório grpc-plain-text-quickstart
.
Configurando seu projeto
Adicione a extensão Quarkus gRPC ao seu arquivo de build:
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-grpc</artifactId>
</dependency>
implementation("io.quarkus:quarkus-grpc")
By default, the quarkus-grpc
extension relies on the reactive programming model.
In this guide we will follow a reactive approach.
Under the dependencies
section of your pom.xml
file, make sure you have the Quarkus REST (formerly RESTEasy Reactive) dependency:
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-rest</artifactId>
</dependency>
implementation("io.quarkus:quarkus-rest")
Se você estiver usando o Maven, certifique-se de que a meta generate-code
do quarkus-maven-plugin
esteja habilitado no seu pom.xml
. Se quiser gerar código a partir de diferentes arquivos proto
para testes, adicione também a meta generate-code-tests
. Observe que nenhuma tarefa/meta adicional é necessária para o plug-in do Gradle.
<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
.
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).
O seu arquivo proto não pode conter option java_generic_services = true; . Os serviços genéricos estão obsoletos e não são compatíveis com os plugins de geração de código do Quarkus.
|
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.
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 jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.Produces;
import jakarta.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
. -
host
configura o host do serviço (aqui é localhost).
Em seguida, abra http://localhost:8080/hello/quarkus em um navegador e deverá receber Hello quarkus
!