The English version of quarkus.io is the official project site. Translated sites are community supported on a best-effort basis.

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:

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

デフォルトでは、 quarkus-grpc エクステンションはリアクティブなプログラミングモデルに依存しています。本ガイドではリアクティブなアプローチを採用します。 pom.xml ファイルの dependencies セクションで、 RESTEasy Reactiveの依存関係を確認してください。

pom.xml
<dependency>
    <groupId>io.quarkus</groupId>
    <artifactId>quarkus-resteasy-reactive</artifactId>
</dependency>
build.gradle
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-plugingenerate-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 ファイルを使いたいかもしれません。この場合は、

  1. protoファイルを含むアーティファクトへの依存関係をプロジェクトに追加する。

  2. 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の実装/タイプ

もうひとつ、QuarkusのgRPCサポートには、現在3種類のgRPCの使用があることにも注意が必要です:

  1. 古いVert.xのgRPC実装で、gRPCサーバーを別に用意(デフォルト)

  2. 新しいVert.x gRPC実装で、既存のHTTPサーバー上に構築

  3. xDS gRPC wrapper over grpc-java with a separate Netty based gRPC server

それぞれの有効化と使用方法については、さらにドキュメントで説明しています。

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サーバー

サービスは サーバー によって 提供されます 。利用可能なサービス( CDIBean )は自動的に登録され、公開されます。

デフォルトでは、通常、サーバーは 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)。

そして、ブラウザで 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>