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.

プロジェクトの設定

pom.xml ファイルを編集して、Quarkus gRPCエクステンションの依存関係を追加します( <dependencies> のすぐ下)。

<dependency>
  <groupId>io.quarkus</groupId>
  <artifactId>quarkus-grpc</artifactId>
</dependency>

By default, the quarkus-grpc extension relies on the reactive programming model. In this guide we will follow a reactive approach. Under the dependencies section of your pom.xml file, make sure you have the RESTEasy Reactive dependency:

<dependency>
    <groupId>io.quarkus</groupId>
    <artifactId>quarkus-resteasy-reactive</artifactId>
</dependency>

pom.xmlgenerate-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 retrieves a version of protoc (the protobuf compiler) from Maven repositories. The retrieved version matches your operating system and CPU architecture. If this retrieved version does not work in your context, you can either force to use a different OS classifier with -Dquarkus.grpc.protoc-os-classifier=your-os-classifier (e.g. osx-x86_64). You can also download the suitable binary and specify the location via -Dquarkus.grpc.protoc-path=/path/to/protoc.

quarkus-maven-plugingenerate-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を持つ依存関係のみをスキャンする

If not specified, the property is set to com.google.protobuf:protobuf-java. To override it, set the quarkus.generate-code.grpc.scan-for-imports property in your application.properties to the desired value, e.g.

quarkus.generate-code.grpc.scan-for-imports=all

proto files from dependencies

In some cases, you may want to use proto files from a different project to generate the gRPC stubs. In this case:

  1. Add a dependency on the artifact that contains the proto file to your project

  2. In application.properties, specify the dependencies you want to scan for proto files.

quarkus.generate-code.grpc.scan-for-proto=<groupId>:<artifactId>

The value of the property may be none, which is the default value, or a comma separated list of groupId:artifactId coordinates.

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.grpc.stub.StreamObserver;
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 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>{grpc-version}</grpc.version>
<protoc.version>{protoc-version}</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.11.1.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 classes from dependencies

When gRPC classes - the classes generated from proto files - are in a dependency of the application, then the dependency needs a Jandex index. The jandex-maven-plugin can be used to create a Jandex index. More information on this topic can be found in the Bean Discovery section of the CDI guide.

<build>
    <plugins>
        <plugin>
            <groupId>org.jboss.jandex</groupId>
            <artifactId>jandex-maven-plugin</artifactId>
            <version>1.2.3</version>
            <executions>
                <execution>
                <id>make-index</id>
                <goals>
                    <goal>jandex</goal>
                </goals>
                </execution>
            </executions>
        </plugin>
    </plugins>
</build>