Getting Started with gRPC
此页面说明了如何在 Quarkus 应用程序中开始使用 gRPC。尽管此页面介绍了如何使用 Maven 配置它,但也可以使用 Gradle。 我们想象您有一个常规的 Quarkus 项目,该项目是从 Quarkus project generator 生成的。默认配置足够使用,但您也可以选择一些扩展(如果您愿意)。
Solution
我们建议您遵循接下来的部分中的说明,按部就班地创建应用程序。然而,您可以直接跳到完成的示例。
克隆 Git 存储库: git clone $${quickstarts-base-url}.git
,或下载 $${quickstarts-base-url}/archive/main.zip[存档]。
解决方案位于 grpc-plain-text-quickstart
directory。
Configuring your project
在构建文件中添加 Quarkus gRPC 扩展:
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-grpc</artifactId>
</dependency>
implementation("io.quarkus:quarkus-grpc")
默认情况下,`quarkus-grpc`扩展依赖于反应式编程模型。在本指南中,我们将遵循反应式方法。在 `pom.xml`文件的 `dependencies`部分下,确保拥有 Quarkus REST(以前称为 RESTEasy Reactive)依赖项:
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-rest</artifactId>
</dependency>
implementation("io.quarkus:quarkus-rest")
如果你使用的是 Maven,请确保在 `pom.xml`中启用了 `quarkus-maven-plugin`的 `generate-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 架构。如果检索到的版本在你的上下文中不起作用,你可以使用 `-Dquarkus.grpc.protoc-os-classifier=your-os-classifier`强制使用不同的 OS 分类器(例如: `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
)。
你的 |
在编码之前,我们需要生成用于实现和使用 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
这些是我们将要使用的类。
Implementing a gRPC service
现在我们有了生成的类,让我们实现我们的 _hello_服务。
使用 Quarkus,实现服务需要实现基于 Mutiny(集成在 Quarkus 中的反应式编程 API)的已生成服务接口,并将其公开为 CDI Bean。在 Mutiny guide中了解有关 Mutiny 的更多信息。服务类必须用 `@io.quarkus.grpc.GrpcService`注解进行注释。
Implementing a service
使用以下内容创建 `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 | 实现生成的 service 接口。 |
3 | 实现服务定义中定义的方法(这里只有一个方法)。 |
你也可以使用 Mutiny 的默认 gRPC API:
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 | Close the response. |
如果你的服务实现逻辑为阻塞(例如使用阻塞 I/O),使用 |
Consuming a gRPC service
在本节中,我们将使用我们公开的服务。为简单起见,我们将从同一个应用程序使用该服务,在实际中这没有意义。
打开现有的 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 生成的 service 接口。 |
3 | Invoke the service. |
我们需要配置应用程序以指示找到 hello
service 的位置。在 src/main/resources/application.properties
文件中,添加以下属性:
quarkus.grpc.clients.hello.host=localhost
-
hello
是@GrpcClient
注释中使用的名称。 -
host
配置服务 host(这里是 localhost)。
然后,在浏览器中打开 [role="bare"][role="bare"]http://localhost:8080/hello/quarkus,你应该会得到 Hello quarkus
!