编辑此页面

gRPC 入门

本页说明如何在 Quarkus 应用程序中开始使用 gRPC。虽然本页描述了如何使用 Maven 进行配置,但也可以使用 Gradle。

假设您有一个常规的 Quarkus 项目,该项目是从 Quarkus 项目生成器生成的。默认配置已足够,但您也可以选择一些扩展(如果需要)。

解决方案

我们建议您按照以下章节中的说明,逐步创建应用程序。但是,您可以直接转到完整的示例。

克隆 Git 存储库:git clone https://github.com/quarkusio/quarkus-quickstarts.git,或者下载一个 存档

解决方案位于 grpc-plain-text-quickstart 目录中。

配置您的项目

将 Quarkus gRPC 扩展添加到您的构建文件中

pom.xml
<dependency>
    <groupId>io.quarkus</groupId>
    <artifactId>quarkus-grpc</artifactId>
</dependency>
build.gradle
implementation("io.quarkus:quarkus-grpc")

默认情况下,quarkus-grpc 扩展依赖于响应式编程模型。在本指南中,我们将遵循响应式方法。在 pom.xml 文件的 dependencies 部分下,确保您具有 Quarkus REST(以前称为 RESTEasy Reactive)依赖项

pom.xml
<dependency>
    <groupId>io.quarkus</groupId>
    <artifactId>quarkus-rest</artifactId>
</dependency>
build.gradle
implementation("io.quarkus:quarkus-rest")

如果您使用的是 Maven,请确保在 pom.xml 中启用了 quarkus-maven-plugingenerate-code 目标。如果您希望为测试生成来自不同 proto 文件的代码,也请添加 generate-code-tests 目标。请注意,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>

有了此配置,您就可以将服务和消息定义放在 src/main/proto 目录中。quarkus-maven-plugin 将从您的 proto 文件生成 Java 文件。

quarkus-maven-plugin 从 Maven 存储库检索 protoc(protobuf 编译器)的版本。检索到的版本与您的操作系统和 CPU 体系结构匹配。如果检索到的版本在您的环境中不起作用,您可以强制使用不同的 OS 分类符(通过 -Dquarkus.grpc.protoc-os-classifier=your-os-classifier,例如 osx-x86_64),或者下载合适的二进制文件并通过 -Dquarkus.grpc.protoc-path=/path/to/protoc 指定其位置。

让我们从一个简单的Hello服务开始。创建 src/main/proto/helloworld.proto 文件,其中包含以下内容

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;
}

proto 文件定义了一个简单的服务接口,其中包含一个方法(SayHello)和交换的消息(包含名称的 HelloRequest 和包含问候消息的 HelloReply)。

您的 proto 文件不得包含 option java_generic_services = true;通用服务已弃用,并且与 Quarkus 代码生成插件不兼容。

在编写代码之前,我们需要生成用于实现和使用 gRPC 服务的类。在终端中运行

$ mvn compile

生成后,您可以查看 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

这些是我们即将使用的类。

不同的 gRPC 实现/类型

另外需要注意的是,Quarkus 的 gRPC 支持目前包括 3 种不同类型的 gRPC 用法

  1. 旧的 Vert.x gRPC 实现,具有单独的 gRPC 服务器(默认)

  2. 新的 Vert.x gRPC 实现,基于现有的 HTTP 服务器

  3. 基于 grpc-javaxDS gRPC 包装器,具有单独的基于 Netty 的 gRPC 服务器

更详细的文档将说明如何启用和使用它们。

实现 gRPC 服务

现在我们有了生成的类,让我们来实现我们的hello服务。

使用 Quarkus,实现服务需要实现基于 Mutiny(Quarkus 集成的响应式编程 API)的生成服务接口,并将其公开为 CDI bean。在 Mutiny 指南中了解更多关于 Mutiny 的信息。服务类必须用 @io.quarkus.grpc.GrpcService 注释进行注解。

实现服务

创建 src/main/java/org/acme/HelloService.java 文件,其中包含以下内容

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 将您的实现公开为 bean。
2 实现生成的服务接口。
3 实现服务定义中定义的方法(这里我们只有一个方法)。

您也可以使用默认的 gRPC API 而不是 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 将您的实现公开为 bean。
2 扩展 ImplBase 类。这是一个生成的类。
3 实现服务定义中定义的方法(这里我们只有一个方法)。
4 构建并发送响应。
5 关闭响应。
如果您的服务实现逻辑是阻塞的(例如,使用阻塞 I/O),请用 @Blocking 注释您的方法。io.smallrye.common.annotation.Blocking 注释指示框架在工作线程而不是 I/O 线程(事件循环)上调用被注解的方法。

gRPC 服务器

这些服务由一个服务器提供。可用的服务(CDI bean)会被自动注册并公开。

默认情况下,服务器在 localhost:9000 上公开,在正常运行时使用明文(无 TLS),在测试时使用 localhost:9001

使用以下命令运行应用程序:mvn quarkus:dev

消耗 gRPC 服务

在本节中,我们将消耗我们公开的服务。为简化起见,我们将从同一个应用程序消耗该服务,这在实际世界中是没有意义的。

打开现有的 org.acme.ExampleResource 类,并将其内容修改为

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 注入服务并配置其名称。名称用于应用程序配置。如果未指定,则使用字段名称:在本例中为 hello
2 使用基于 Mutiny API 的生成服务接口。
3 调用服务。

我们需要配置应用程序以指示 hello 服务的位置。在 src/main/resources/application.properties 文件中,添加以下属性

quarkus.grpc.clients.hello.host=localhost
  • hello 是在 @GrpcClient 注释中使用的名称。

  • host 配置服务主机(此处为 localhost)。

然后,在浏览器中打开 https://:8080/hello/quarkus,您应该会收到 Hello quarkus

打包应用程序

与任何其他 Quarkus 应用程序一样,您可以使用:mvn package 来打包它。您也可以使用:mvn package -Dnative 将应用程序打包成原生可执行文件。

相关内容