gRPCを始めるには
このページでは、QuarkusアプリケーションでgRPCを使い始める方法を説明します。このページではMavenでの設定方法を説明していますが、Gradleを使用することも可能です。
ここでは、 Quarkusプロジェクトジェネレータ から生成された通常のQuarkusプロジェクトを想像してみましょう。デフォルトの設定で十分ですが、必要に応じていくつかのエクステンションを選択することもできます。
ソリューション
次の章で紹介する手順に沿って、ステップを踏んでアプリを作成することをお勧めします。ただし、完成した例にそのまま進んでも構いません。
Gitレポジトリをクローンするか git clone https://github.com/quarkusio/quarkus-quickstarts.git 、 アーカイブ をダウンロードします。
このソリューションは grpc-plain-text-quickstart ディレクトリ にあります。
プロジェクトの設定
pom.xml ファイルを編集して、Quarkus gRPCエクステンションの依存関係を追加します( <dependencies> のすぐ下)。
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-grpc</artifactId>
</dependency>
デフォルトでは、 quarkus-grpc エクステンションはリアクティブなプログラミングモデルに依存しています。本ガイドではリアクティブなアプローチを採用します。 pom.xml ファイルの dependencies セクションで、 RESTEasy Reactiveの依存関係を確認してください。
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-resteasy-reactive</artifactId>
</dependency>
pom.xml で generate-code ゴールの quarkus-maven-plugin が有効になっていることを確認してください。テスト用に異なる 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 でその場所を指定することもできます。
quarkus-maven-plugin の generate-code ゴールを使用する代わりに、 protobuf-maven-plugin を使用してこれらのファイルを生成することができます。詳細は protoファイルからprotobuf-maven-pluginで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 ) を持つシンプルなサービスインターフェースを定義しています。
コーディングの前に、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 座標のコンマ区切りリストとなります。
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 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 | サービスをインジェクトし、その名前を設定します。この名前は、アプリケーションの設定で使用されます。指定しない場合、フィールド名が代わりに使用されます : このケースでは 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 と表示されるはずです!
アプリケーションのパッケージング
他のQuarkusアプリケーションと同様に、 mvn package でパッケージングすることができます。また、 mvn package -Pnative でアプリケーションをネイティブ実行可能ファイルにパッケージングすることもできます。
protoファイルからprotobuf-maven-pluginでJavaファイルを生成する
Quarkusのコード生成を使用して proto ファイルのスタブを生成する代わりに、 protobuf-maven-plugin を使うこともできます。
そのためには、まず <properties> セクションで以下の 2 つのプロパティーを定義します。
<grpc.version>1.53.0</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>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 | 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.0.5</version>
<executions>
<execution>
<id>make-index</id>
<goals>
<goal>jandex</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>