gRPC入門
このページでは、QuarkusアプリケーションでgRPCを使い始める方法を説明します。このページではMavenでの設定方法を説明していますが、Gradleを使用することも可能です。
ここでは、 Quarkusプロジェクトジェネレータ から生成された通常のQuarkusプロジェクトを想像してみましょう。デフォルトの設定で十分ですが、必要に応じていくつかのエクステンションを選択することもできます。
ソリューション
次のセクションで紹介する手順に沿って、ステップを踏んでアプリを作成することをお勧めします。ただし、完成した例にそのまま進んでも構いません。
Gitレポジトリをクローンするか git clone https://github.com/quarkusio/quarkus-quickstarts.git
、 アーカイブ をダウンロードします。
The solution is located in the grpc-plain-text-quickstart
directory.
プロジェクトの設定
Add the Quarkus gRPC extension to your build file:
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-grpc</artifactId>
</dependency>
implementation("io.quarkus:quarkus-grpc")
デフォルトでは、 quarkus-grpc
エクステンションはリアクティブなプログラミングモデルに依存しています。本ガイドではリアクティブなアプローチを採用します。 pom.xml
ファイルの dependencies
セクションで、 RESTEasy Reactiveの依存関係を確認してください。
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-resteasy-reactive</artifactId>
</dependency>
implementation("io.quarkus:quarkus-resteasy-reactive")
If you are using Maven, make sure you have the 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>
この設定では、サービスとメッセージの定義を 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
でその場所を指定することもできます。
quarkus-maven-plugin
の generate-code
ゴールを使用する代わりに、これらのファイルを生成するために protobuf-maven-plugin
を使用することができます。詳細については、 protobuf-maven-pluginを使用したprotoからのJavaファイルの生成 セクションを参照してください。
まずは簡単な 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
これらは、これから使うクラスファイルです。
proto
ファイルのインポート
Protocol Buffers仕様では、 proto
ファイルをインポートする方法を提供しています。Quarkusのコード生成メカニズムでは、 quarkus.generate-code.grpc.scan-for-imports
プロパティーを以下のいずれかに設定することで、インポートの可能性をスキャンするための依存関係の範囲を制御することができます。
-
all
- すべての依存関係をスキャンする -
none
- 依存関係をスキャンしないで、src/main/proto
またはsrc/test/proto
のみで定義されたものを利用する -
groupId1:artifactId1,groupId2:artifactId2
- リスト内のグループIDとアーティファクトIDを持つ依存関係のみをスキャンする
指定されていない場合、このプロパティは com.google.protobuf:protobuf-java
に設定されます。これを上書きするには、application.propertiesに quarkus.generate-code.grpc.scan-for-imports
を以下を例に必要な値を設定します。
quarkus.generate-code.grpc.scan-for-imports=all
依存関係にある proto
ファイル
場合によっては、gRPC スタブを生成するために別のプロジェクトの proto
ファイルを使いたいかもしれません。この場合は、
-
protoファイルを含むアーティファクトへの依存関係をプロジェクトに追加する。
-
application.properties
で、proto ファイルをスキャンしたい依存関係を指定します。
quarkus.generate-code.grpc.scan-for-proto=<groupId>:<artifactId>
プロパティの値は、デフォルト値である none
、または groupId:artifactId
座標のコンマ区切りリストとなります。
option java_generic_services = true; は、それを含む proto ファイルから自動的に削除されます。
|
依存関係に多くのプロトファイルが含まれていて、その一部だけのクラスを生成したい場合は、依存関係ごとにグロブパターンを指定することができます。マッチするパスは、依存関係内のパス src/main/resources
からの相対パスです。
たとえば、application.properties
で以下のプロパティーを設定すると、
quarkus.generate-code.grpc.scan-for-proto-includes."<groupId>\:<artifactId>"=foo/**,bar/**,banana/a-proto.proto
quarkus.generate-code.grpc.scan-for-proto-excludes."<groupId>\:<artifactId>"=foo/private/**,bar/another-proto.proto
以下が含まれます。
-
foo/
ディレクトリーの全てのファイルと`foo/private/` とそのサブディレクトリーを除く、サブディレクトリー、 -
bar/
ディレクトリの全てのファイルとanother-proto.proto
を除くすべてのそのサブディレクトリ。 -
banana/a-proto.proto
ファイル
プロパティキーに含まれる`:` は、エスケープする必要があります。 |
gRPCサービスの実装
生成されたクラスができたので、 hello サービスを実装してみましょう。
Quarkusは、Quarkusに統合されたReactive Programming APIであるMutinyを使用した追加モデルも提供しています。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 | サービス定義で定義されたメソッドを実装します(ここでは1つのメソッドを使用しています)。 |
また、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 | サービス定義で定義されたメソッドを実装します(ここでは1つのメソッドを使用しています)。 |
4 | レスポンスを構築して送信します。 |
5 | レスポンスを閉じます。 |
サービスの実装ロジックがブロッキングである (例えば、ブロッキング I/O を使用する) 場合には、メソッドに @Blocking をアノテーションします。 io.smallrye.common.annotation.Blocking アノテーションは、I/O スレッド (イベントループ) の代わりにワーカースレッドでアノテーションされたメソッドを呼び出すようにフレームワークに指示します。
|
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)。
そして、ブラウザで http://localhost:8080/hello/quarkus を開くと、 Hello quarkus
と表示されるはずです!
アプリケーションのパッケージング
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 -Dnative
.
protoファイルからprotobuf-maven-pluginでJavaファイルを生成する
Quarkusのコード生成を使用して proto
ファイルのスタブを生成する代わりに、 protobuf-maven-plugin
を使うこともできます。
そのためには、まず <properties>
セクションで以下の 2 つのプロパティーを定義します。
<grpc.version>1.57.2</grpc.version>
<protoc.version>3.22.0</protoc.version>
これらは gRPC のバージョンと protoc
のバージョンを設定します。
そして、 build
セクションに os-maven-plugin
のエクステンションと protobuf-maven-plugin
の設定を追加します。
<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>3.4.1</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 | gRPCサービス定義( proto ファイル)からスタブクラスを生成する protobuf-maven-plugin |
2 | クラス生成には、OS固有の protoc というツールを使用しています。そのため、OSと互換性のある実行可能ファイルを対象に os-maven-plugin を使用しています。 |
この設定は、Quarkusの開発経験に合わせてMutinyを使用してデフォルトのgRPCクラスとクラスを生成するように、 protobuf-maven-plugin に指示します。
|
quarkus-maven-plugin の代わりに protobuf-maven-plugin を利用する場合、 proto ファイルを更新するたびに、( mvn compile を使用して) クラスを再生成する必要があります。
|
依存関係にあるgRPCクラス
gRPCクラス( proto
ファイルから生成されたクラス)がアプリケーションの依存関係にある場合、その依存関係にはJandexインデックスが必要です。 jandex-maven-plugin
は、Jandexインデックスを作成するために使用できます。このトピックの詳細については、CDIガイドのBean Discoveryセクションを参照してください。
<build>
<plugins>
<plugin>
<groupId>io.smallrye</groupId>
<artifactId>jandex-maven-plugin</artifactId>
<version>3.1.3</version>
<executions>
<execution>
<id>make-index</id>
<goals>
<goal>jandex</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>