1. 序章

gRPCは、Googleが開発したオープンソースのRPC(リモートプロシージャコール)プラットフォームであり、あらゆる種類の環境およびデータセンター間で高性能で効率的な通信を提供します。 さらに、負荷分散、トレース、ヘルスチェック、および認証のgRPCのプラグイン可能なサポートにより、分散コンピューティングおよびマイクロサービスで使用するのに適した候補になります。

gRPCでは、クライアントアプリケーションは、分散アプリケーションとサービスの複雑さを隠す生成されたスタブを使用して、サーバーアプリケーション上のメソッドを呼び出します

このチュートリアルでは、gRPCコンポーネントについて説明し、KotlinでgRPCサーバーとクライアントを実装する方法を説明します。

2. コンポーネント

gRPCはサービス定義から始まります。 サービス定義はサービスのインターフェースであり、メソッド、パラメーター、および期待される戻りタイプが含まれています。

次に、定義されたサービスインターフェイスに基づいて、クライアントはスタブを使用してサーバーを呼び出します。 一方、サーバーはインターフェースのサービスを実装し、gRPCサーバーを実行してクライアントの要求を処理します。

gRPCはデフォルトで、サービス定義とペイロードを記述するためのインターフェース記述言語としてProtobufを使用します。 ただし、 Protobuf の代わりに、Gsonなどの他のライブラリを使用してエンコードおよびデコードすることもできます。

gRPCがどのように機能するかをある程度理解したので、実装を見てみましょう。

3. 依存関係

gRPCの依存関係をPOMに追加することから始めましょう:

<dependency>
    <groupId>io.grpc</groupId>
    <artifactId>grpc-netty</artifactId>
    <version>1.46.0</version>
</dependency>
<dependency>
    <groupId>io.grpc</groupId>
    <artifactId>grpc-protobuf</artifactId>
    <version>1.39.0</version>
</dependency>
<dependency>
    <groupId>io.grpc</groupId>
    <artifactId>grpc-stub</artifactId>
    <version>1.46.0</version>
</dependency>
<dependency>
    <groupId>io.grpc</groupId>
    <artifactId>grpc-kotlin-stub</artifactId>
    <version>1.2.0</version>
</dependency>
<dependency>
    <groupId>com.google.protobuf</groupId>
    <artifactId>protobuf-kotlin</artifactId>
    <version>3.18.1</version>
</dependency>
<dependency>
    <groupId>com.google.protobuf</groupId>
    <artifactId>protobuf-java</artifactId>
    <version>3.18.1</version> 
</dependency>

4. プロトファイル

次に、.protoファイルでサービスを定義しましょう。 このチュートリアルでは、Javaチュートリアルで以前に使用したものと同じサービス定義を使用します。

syntax = "proto3";

package com.baeldung.grpc.helloworld;

option java_multiple_files = true;

service HelloService {
  rpc hello (HelloRequest) returns (HelloReply) {}
}

message HelloRequest {
  string name = 1;
}

message HelloReply {
  string message = 1;
}

これらのプロトファイルをコードで使用するには、それらのスタブを作成する必要があります。 この目標を達成するために、プロトコルバッファコンパイラprotocを使用します。

protoc --plugin=protoc-gen-grpc-java=build/exe/java_plugin/protoc-gen-grpc-java \
  --grpc-java_out="$OUTPUT_FILE" --proto_path="$DIR_OF_PROTO_FILE" "$PROTO_FILE"

さらに、以下に示すように、このスタブ作成ステップをpom.xmlに埋め込むという簡単なオプションがあります。

5. Mavenプラグイン

次に、 org.xolstice.maven.plugins:protobuf-maven-pluginプラグインをpom.xml に追加して、プロトからリクエスト、レスポンス、スタブを作成できるようにします。 Maven compileゴールを実行するときのファイル。

これは、grpc-kotlin実装を利用します。

<plugin>
    <groupId>org.xolstice.maven.plugins</groupId>
    <artifactId>protobuf-maven-plugin</artifactId>
    <version>0.6.1</version>
    <executions>
        <execution>
            <id>compile</id>
            <goals>
                <goal>compile</goal>
            </goals>
            <configuration>
                <protocArtifact>com.google.protobuf:protoc:${protobuf.version}:exe:${os.detected.classifier}</protocArtifact>
                <pluginId>grpc-java</pluginId>
                <pluginArtifact>io.grpc:protoc-gen-grpc-java:${grpc.version}:exe:${os.detected.classifier}</pluginArtifact>
                <protocPlugins>
                    <protocPlugin>
                        <id>grpc-kotlin</id>
                        <groupId>io.grpc</groupId>
                        <artifactId>protoc-gen-grpc-kotlin</artifactId>
                        <version>${grpc.kotlin.version}</version>
                        <classifier>jdk7</classifier>
                        <mainClass>io.grpc.kotlin.generator.GeneratorRunner</mainClass>
                    </protocPlugin>
                </protocPlugins>
            </configuration>
        </execution>
    </executions>
</plugin>

6. サーバーの実装

サービスの機能を実装するために、HelloServiceCoroutineImplBaseをオーバーライドすることから始めましょう。

class HelloService : HelloServiceGrpcKt.HelloServiceCoroutineImplBase() {
    override suspend fun hello(request: HelloRequest): HelloReply {
        return HelloReply.newBuilder()
            .setMessage("Hello, ${request.name}")
            .build()
    }
}

次に、HelloServiceを使用してgRPCサーバーを起動できます。

fun helloServer() {
    val helloService = HelloService()
    val server = ServerBuilder
        .forPort(15001)
        .addService(helloService)
        .build()

    Runtime.getRuntime().addShutdownHook(Thread {
        server.shutdown()
        server.awaitTermination()
    })

    server.start()
    server.awaitTermination()
}

fun main(args: Array<String>) {
    helloServer()
}

7. クライアントの実装

クライアントを設定するには、 ManagedChannel を作成しましょう。

val channel = ManagedChannelBuilder.forAddress("localhost", 15001)
    .usePlaintext()
    .build()

gRPCチャネルを使用して、クライアントは指定されたホストとポート上のgRPCサーバーに接続します。

それでは、スタブを作成しましょう。

val stub = HelloServiceGrpc.newBlockingStub(channel)

最後に、リクエストを作成してサーバーを呼び出しましょう。

val response = stub.hello(HelloRequest.newBuilder().setName("Baeldung").build())

ここでは、ブロッキングスタブを作成しますが、futureスタブまたは非同期スタブのオプションもあります。

将来のスタブを呼び出して、次のように応答を取得できます。 com.google.common.util.concurrent.ListenableFuture。 次に、通話をキャンセルするか、タイムアウトで応答を取得する可能性があります。

HelloServiceGrpc.newFutureStub(channel)

さらに、非同期スタブを作成し、コールバックでリアクティブな方法で応答を取得できます。

HelloServiceGrpc.newStub(channel).hello(
    HelloRequest.newBuilder().setName("Baeldung").build(), object: StreamObserver<HelloReply> {
        override fun onNext(response: HelloReply?) {
            //consume response
        }

        override fun onError(throwable: Throwable?) {
            //handle error
        }

        override fun onCompleted() {
            //on complete
        }
    }
)

8. 結論

この記事では、gRPCと、Kotlinを使用してサーバー側とクライアント側にgRPCを実装する方法について説明しました。

いつものように、この記事の完全なソースコードは、GitHubから入手できます。