gRPC
Google リモートプロシージャコール (gRPC) は、バイナリメッセージを使用してクライアントとサーバー間の通信を可能にする高性能な RPC フレームワークです。Spring Boot は、クライアントおよびサーバー両方の gRPC アプリケーションの開発とテストをサポートしています。
gRPC で使用される基盤となるメッセージ形式はプロトコルバッファであり、これにより様々なプログラミング言語でメッセージを作成および消費することが可能になります。
サービス定義
gRPC アプリケーションを開発するには、まず Protocol Buffers サービス定義ファイルが必要です。.proto ファイルは、アプリケーションが利用または提供できるサービスとメッセージを定義します。
Here’s an example of a typical .proto file that uses the proto3 revision (英語) of the protocol buffers language:
syntax = "proto3";
option java_package = "com.example.grpc.proto";
option java_multiple_files = true;
service HelloWorld {
rpc SayHello (HelloRequest) returns (HelloReply) {}
}
message HelloRequest {
string name = 1;
}
message HelloReply {
string message = 1;
} このファイルは、HelloReqest メッセージを受け取り、HelloReply メッセージを返す単一のメソッドを持つ HelloWorld サービスを定義します。HelloReqest メッセージには name 文字列フィールドが含まれます。HelloReply メッセージには message 文字列フィールドが含まれます。
java_package と java_multiple_files のオプションを除いて、.proto ファイルには Java プログラミング言語に特有のものは何も含まれていません。
Java コードの生成
.proto ファイルは言語に依存しないため、使用可能な Java コードに変換するプロセスが必要です。生成されたコードを使用して、実行中のサービスに対してリモートプロシージャ呼び出しを行うか、サービスを独自に実装して他のユーザーが呼び出せるようにすることができます。
コード生成に使用する具体的な手順は、使用するビルドシステムによって異なります。Spring Boot は Maven と Gradle の両方の protobuf プラグインをサポートしていますが、ご自身にとって最適なソリューションを自由に選択してください。
Maven プラグインの使用
Spring Boot には、io.github.ascopes:protobuf-maven-plugin および Maven プラグインの依存関係管理機能が含まれています。spring-boot-starter-parent POM を使用している場合は、すぐに使える適切な設定も提供されます。
以下は、プラグインを使用する典型的な Maven POM ファイルの例です。
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>4.1.0</version>
</parent>
<groupId>com.example</groupId>
<artifactId>myproject</artifactId>
<version>0.0.1-SNAPSHOT</version>
<build>
<plugins>
<plugin>
<groupId>io.github.ascopes</groupId>
<artifactId>protobuf-maven-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project> 上記の POM は spring-boot-starter-parent を継承しているため、以下のようになります。
protocバージョンの設定。binary-mavenプラグインの設定。generateゴールの実行構成。
.proto のファイルを src/main/proto に追加する必要があります。
If you don’t use spring-boot-starter-parent, or you want to configure the plugin directly, refer to the protobuf-maven-plugin documentation (英語) . If you use Spring Boot’s dependency management the ${protobuf-java.version} and ${grpc-java.version} properties will be useful. |
Gradle プラグインの使用
Spring Boot には、com.google.protobuf:protobuf-gradle-plugin および Gradle プラグインの依存関係管理機能が含まれています。さらに、spring-boot-gradle-plugin は protobuf プラグインの存在を検知し、適切に設定を行います。
以下に、プラグインを使用した典型的な Gradle ファイルを示します。
plugins {
id 'java'
id 'org.springframework.boot' version '4.1.0'
id 'io.spring.dependency-management' version '1.1.7'
id 'com.google.protobuf' version '0.9.6'
}
group = 'com.example'
version = '0.0.1-SNAPSHOT'
java {
toolchain {
languageVersion = JavaLanguageVersion.of(17)
}
}
repositories {
mavenCentral()
} この gradle ファイルは org.springframework.boot と com.google.protobuf の両方のプラグインを使用しているため、以下のようになります。
protocバージョンの設定。protoc-gen-grpc-javaバージョンの設定。
.proto のファイルを src/main/proto に追加する必要があります。
If you don’t use org.springframework.boot plugin, or you want to configure the plugin directly, refer to the protobuf-gradle-plugin documentation [GitHub] (英語) . |
gRPC サーバーアプリケーションの作成
Spring Boot は、サーバーアプリケーションで使用できる spring-boot-grpc-server モジュールと spring-boot-starter-grpc-server スターター POM を提供します。
実際のサーバーコードを記述するには、.proto ファイルから生成された基本クラスを 1 つ以上拡張し、Spring Bean として公開する必要があります。Spring gRPC は、BindableService (英語) を実装する Bean を自動的に gRPC サーバーとして公開します。.proto で生成されたクラスはすべて BindableService (英語) を実装しているため、Bean として追加するだけで、gRPC 経由で公開できます。
| For more details see the Spring gRPC documentation. |
次の例は、上記の .proto ファイルに含まれる HelloWorld サービスをどのように実装できるかを示しています。この例では、@GrpcService (Javadoc) アノテーションを使用し、コードがコンポーネントスキャンによって検出されるパッケージ内にあることを前提としています。
Java
Kotlin
import io.grpc.stub.StreamObserver;
import org.springframework.grpc.server.service.GrpcService;
@GrpcService
public class MyHelloWorldService extends HelloWorldGrpc.HelloWorldImplBase {
@Override
public void sayHello(HelloRequest request, StreamObserver<HelloReply> responseObserver) {
String message = "Hello '%s'".formatted(request.getName());
HelloReply reply = HelloReply.newBuilder().setMessage(message).build();
responseObserver.onNext(reply);
responseObserver.onCompleted();
}
}import io.grpc.stub.StreamObserver
import org.springframework.grpc.server.service.GrpcService
@GrpcService
class MyHelloWorldService : HelloWorldGrpc.HelloWorldImplBase() {
override fun sayHello(request: HelloRequest, responseObserver: StreamObserver<HelloReply>) {
val message = "Hello '${request.getName()}'"
val reply = HelloReply.newBuilder().setMessage(message).build()
responseObserver.onNext(reply)
responseObserver.onCompleted()
}
} アプリケーションが spring-boot-starter-grpc-server を使用する場合、Netty がポート 9090 でリッスンするサーバー実装として使用されます。
You can test your application using grpcurl [GitHub] (英語) :
$ grpcurl -d '{"name":"Spring"}' -plaintext localhost:9090 HelloWorld.SayHello{
"message": "Hello 'Spring'"
}Netty シェードサーバーへの切り替え
spring-boot-starter-grpc-server スターター POM に含まれる Netty のバージョンが、使用している他のライブラリと互換性がないことが判明した場合は、「シェーディング」バージョンに切り替えることができます。
切り替えるには、io.grpc:grpc-netty を除外して io.grpc:grpc-netty-shaded を含めることができます。例:
Maven
Gradle
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-grpc-server</artifactId>
<exclusions>
<!-- Exclude the gRPC Netty dependency -->
<exclusion>
<groupId>io.grpc</groupId>
<artifactId>grpc-netty</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- Use gRPC Netty Shaded instead -->
<dependency>
<groupId>io.grpc</groupId>
<artifactId>grpc-netty-shaded</artifactId>
</dependency>dependencies {
implementation('org.springframework.boot:spring-boot-starter-grpc-server') {
// Exclude the gRPC Netty dependency
exclude group: 'io.grpc', module: 'grpc-netty'
}
// Use gRPC Netty Shaded instead
implementation "io.grpc:grpc-netty-shaded"
}サーブレットコンテナーへの切り替え
Netty ではなく、Tomcat などの通常のサーブレットコンテナーを使用して gRPC サービスを公開することも可能です。そのためには、サーブレットコンテナーが HTTP/2 をサポートするように設定する必要があります。
サーブレット gRPC 実装に切り替えるには、io.grpc:grpc-netty を除外し、io.grpc:grpc-servlet-jakarta を含めることができます。例:
Maven
Gradle
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webmvc</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-grpc-server</artifactId>
<exclusions>
<!-- Exclude the gRPC Netty dependency -->
<exclusion>
<groupId>io.grpc</groupId>
<artifactId>grpc-netty</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- Use gRPC Servlet Jakarta instead -->
<dependency>
<groupId>io.grpc</groupId>
<artifactId>grpc-servlet-jakarta</artifactId>
</dependency>dependencies {
implementation('org.springframework.boot:spring-boot-starter-webmvc') {
implementation('org.springframework.boot:spring-boot-starter-grpc-server') {
// Exclude the gRPC Netty dependency
exclude group: 'io.grpc', module: 'grpc-netty'
}
// Use gRPC Servlet Jakarta instead
implementation "io.grpc:grpc-servlet-jakarta"
} サーブレットコンテナーの依存関係を含めることを忘れないでください。たとえば、spring-boot-starter-tomcat を使用して、server.http2.enabled を true に設定します。 |
サーブレットコンテナーを使用する場合、特定の gRPC サーバー構成プロパティは関係なく無視されます。例: server.port が Web サーバーポートを設定するために使用されたため、spring.grpc.server.port は無視されます。 |
SSL サポート
SSL は、SSL バンドルを使用して grpc-netty サーバーと grpc-netty-shaded サーバーの両方で設定できます。SSL バンドルの宣言方法の詳細については、SSL core documentation を参照してください。
バンドルが定義されたら、gRPC サーバーアプリケーションで以下のプロパティを使用してバンドルを使用できます。
プロパティ
YAML
spring.grpc.server.ssl.bundle=mysslbundlespring:
grpc:
server:
ssl:
bundle: mysslbundle クライアント認証は、spring.grpc.server.ssl.client-auth を optional または require に設定することによっても構成できます。
たとえばテストを支援するために、サーバーの SSL サポートを一時的に無効にするには、spring.grpc.server.ssl.enabled を false に設定できます。 |
インプロセスサーバーの使用
クラスパスに io.grpc:grpc-inprocess の依存関係を追加し、spring.grpc.server.inprocess.name プロパティを定義することで、インプロセスサーバーを実行できます。このモードでは、通常のサーバーファクトリに加えて、インプロセスサーバーファクトリも自動的に構成されます。
ご提供いただいた名前は、in-process:<name> の形式でクライアントチャネルのターゲットとして使用できます。
リフレクション
When it’s available, Spring Boot will auto-configure the gRPC Reflection service (英語) . This allows clients to browse the metadata of your services and download their .proto files.
リフレクションサービスは、オプションの依存関係である io.grpc:grpc-services ライブラリに含まれています。自動構成を適用するには、プロジェクトにこの依存関係を追加する必要があります。
io.grpc:grpc-services ライブラリをお持ちで、リフレクションを自動構成したくない場合は、spring.grpc.server.reflection.enabled を false に設定できます。 |
サーバーの状態
gRPC サーバーは、標準サービス API(health/v1 [GitHub] (英語) )を使用して健全性情報を提供できます。これにより、クライアントはサーバーサービスの健全性を確認し、トラフィックを適切にルーティングできます。
Spring Boot は、独自の spring-boot-health モジュールと標準の gRPC ヘルスサービスとの間の橋渡し役を果たします。io.grpc:grpc-services モジュールと org.springframework.boot:spring-boot-health モジュールがクラスパス上に存在する場合、ヘルス情報が提供されます。
ヘルス指標を公開したくない場合は、spring.grpc.server.health.enabled を false に設定できます。 |
サービス別ヘルスマッピング
デフォルトでは、利用可能なすべてのヘルスインジケーターを使用して、サーバー全体のステータス("")に関するヘルス情報が提供されます。
また、特定のサービスに対して、ヘルス指標のサブセットのみを含めることで、より詳細なヘルス情報を提供することも可能です。サービスごとに、カスタムマッピングおよび順序付けルールを定義することもできます。
例: 以下の設定では、db および redis インジケーターのみを使用して "myservice" の健全性を提供します。
プロパティ
YAML
spring.grpc.server.health.service.myservice.include[0]=db
spring.grpc.server.health.service.myservice.include[1]=redisspring:
grpc:
server:
health:
service:
myservice:
include:
- db
- redis サービス固有の状態情報のみを提供したい場合は、spring.grpc.server.health.include-overall-health を false に設定することで、サーバー全体の状態情報表示を無効にできます。 |
プッシュ構成
Web ベースのヘルスチェックとは異なり、gRPC のヘルス情報はプルではなくプッシュで定期的に送信されます。デフォルトでは、最初のヘルス情報のプッシュはアプリケーション起動後 5 秒後に行われ、その後は 5 秒ごとに送信されます。
これを微調整するには、以下のプロパティを使用できます。
プロパティ
YAML
spring.grpc.server.health.schedule.period=5m
spring.grpc.server.health.schedule.delay=2sspring:
grpc:
server:
health:
schedule:
period: 5m
delay: 2s ヘルス状態の更新情報を別の方法で送信したい場合は、spring.grpc.server.health.schedule.enabled を false に設定することもできます。 |
gRPC サーバーアプリケーションのセキュリティ保護
Netty ベースのサーバー
Spring gRPC には、Spring Security を使用して Netty ベースのサーバーアプリケーションを宣言的に保護できる機能が含まれています。これは、通常の Web アプリケーションを保護する際に使用するパターンと同様のものです。
Spring Boot は、GrpcSecurity (Javadoc) および SecurityGrpcExceptionHandler (Javadoc) の両方の Bean に対して自動構成機能を提供します。通常、gRPC アプリケーションは、gRPC サービス Bean に @PreAuthorize (Javadoc) アノテーション、または AuthenticationProcessInterceptor (Javadoc) Bean を使用して保護されます。
For more details, please see the Spring gRPC documentation.
サーブレットコンテナーベースのサーバー
If your gRPC server is running within a standard Servlet Container, you can use typical web security configuration to secure your application. Spring Boot will auto-configre GrpcServerExecutorProvider (Javadoc) and SecurityContextServerInterceptor (Javadoc) beans to ensure that Spring Security works correctly.
クロスサイトリクエストフォージェリ(CSRF)対策は gRPC プロトコルと互換性がないため、すべての gRPC リクエストでデフォルトで無効になっています。独自の CSRF 対策を設定したい場合は、spring.grpc.server.security.csrf.enabled を false に設定することで無効にできます。
手動でのセキュリティ設定を支援するために、Spring Boot は gRPC サービス用のリクエストマッチャーを提供します。マッチはサーブレットスタックとリアクティブスタックの両方で使用できます。例: 以下は "special" を除くすべての gRPC サービスを含みます。
Java
Kotlin
import org.springframework.boot.grpc.server.autoconfigure.security.web.servlet.GrpcRequest;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.web.SecurityFilterChain;
import static org.springframework.security.config.Customizer.withDefaults;
@Configuration(proxyBeanMethods = false)
public class MySecurityConfiguration {
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) {
http.securityMatcher(GrpcRequest.toAnyService().excluding("special"));
http.authorizeHttpRequests((requests) -> requests.anyRequest().hasRole("GRPC_ADMIN"));
http.httpBasic(withDefaults());
return http.build();
}
}import org.springframework.boot.grpc.server.autoconfigure.security.web.servlet.GrpcRequest
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import org.springframework.security.config.Customizer.withDefaults
import org.springframework.security.config.annotation.web.builders.HttpSecurity
import org.springframework.security.web.SecurityFilterChain
@Configuration(proxyBeanMethods = false)
class MySecurityConfiguration {
@Bean
fun securityFilterChain(http: HttpSecurity): SecurityFilterChain {
http.securityMatcher(GrpcRequest.toAnyService().excluding("special"))
http.authorizeHttpRequests { requests -> requests.anyRequest().hasRole("GRPC_ADMIN") }
http.httpBasic(withDefaults())
return http.build()
}
} リアクティブ型の試合には org.springframework.boot.grpc.server.autoconfigure.security.web.servlet.GrpcRequest (Javadoc) を使用してください。 |
OAuth2 リソースサーバー
OAuth2 (英語) は広く利用されている認証フレームワークです。Spring Boot の OAuth2 リソースサーバーのサポートは gRPC と互換性があり、通常の方法で設定できます。
gRPC サーバーアプリケーションで使用する OAuth2 リソースサーバーの設定方法の詳細については、「セキュリティ」の "OAuth2" セクションを参照してください。
gRPC クライアントアプリケーションの作成
Spring Boot は、クライアントアプリケーションで使用できる spring-boot-grpc-client モジュールと spring-boot-starter-grpc-client スターター POM を提供します。
クライアントは、.proto ファイルから生成された「スタブ」クラスを 1 つ以上インポートすることで、リモート gRPC サービスを呼び出すことができます。使用するスタブクラスをインポートするには、@ImportGrpcClients (Javadoc) アノテーションを使用できます。
各インポートには、論理チャネル名またはリモートサーバーのベース URL のいずれかである target が含まれます。通常、ターゲットをハードコードするよりもチャネル名を使用することをお勧めします。
典型的な例を挙げましょう。
Java
Kotlin
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.grpc.client.ImportGrpcClients;
@SpringBootApplication(proxyBeanMethods = false)
@ImportGrpcClients(target = "hello", types = HelloWorldGrpc.HelloWorldBlockingStub.class)
public class MyApplication {
public static void main(String[] args) {
SpringApplication.run(MyApplication.class, args);
}
}import org.springframework.boot.autoconfigure.SpringBootApplication
import org.springframework.boot.docs.features.springapplication.MyApplication
import org.springframework.boot.runApplication
import org.springframework.grpc.client.ImportGrpcClients
@SpringBootApplication(proxyBeanMethods = false)
@ImportGrpcClients(target = "hello", types = [HelloWorldGrpc.HelloWorldBlockingStub::class])
class MyApplication
fun main(args: Array<String>) {
runApplication<MyApplication>(*args)
}target を指定しない場合は、「デフォルト」が使用されます。 |
@ImportGrpcClients (Javadoc) の basePackageClasses または basePackages 属性を使用すると、指定されたパッケージ内のすべてのスタブをインポートできます。 |
チャネルプロパティ
@ImportGrpcClients (Javadoc) の target 属性で論理チャネル名を使用する場合、Spring Boot が実際に呼び出すべき gRPC サーバーを見つけることができるように、いくつかのプロパティを指定する必要があります。
そのためには、spring.grpc.channel.<name>.* のプロパティを使用してエントリを追加します。通常は、実際の target と、チャネル固有のその他の設定を構成します。
例: 以下の設定により、myservice は static://grpc.example.com:9090 の実際のターゲットを使用するように構成されます。また、キープアライブタイムアウトと許可される最大メッセージサイズも変更されます。
プロパティ
YAML
spring.grpc.client.channel.myservice.target=static://grpc.example.com:9090
spring.grpc.client.channel.myservice.inbound.keepalive.timeout=40s
spring.grpc.client.channel.myservice.inbound.message.max-size=8MBspring:
grpc:
client:
channel:
myservice:
target: static://grpc.example.com:9090
inbound:
keepalive:
timeout: 40s
message:
max-size: 8MB茎の短い Bean を使う
@ImportGrpcClients (Javadoc) アノテーションが適切に配置され、プロパティが記述されていれば、他の Bean と同様にスタブを使用できます。
例: HelloWorldStub が ApplicationRunner Bean に注入される例です。
Java
Kotlin
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.boot.docs.io.grpc.client.stubbeans.HelloWorldGrpc.HelloWorldBlockingStub;
import org.springframework.stereotype.Component;
@Component
class MyApplicationRunner implements ApplicationRunner {
private final HelloWorldBlockingStub helloStub;
MyApplicationRunner(HelloWorldGrpc.HelloWorldBlockingStub helloStub) {
this.helloStub = helloStub;
}
@Override
public void run(ApplicationArguments args) throws Exception {
HelloRequest request = HelloRequest.newBuilder().setName("Spring").build();
HelloReply reply = this.helloStub.sayHello(request);
System.out.println(reply.getMessage());
}
}import org.springframework.boot.ApplicationArguments
import org.springframework.boot.ApplicationRunner
class MyApplicationRunner(val helloStub: HelloWorldGrpc.HelloWorldBlockingStub) : ApplicationRunner {
override fun run(args: ApplicationArguments) {
val request = HelloRequest.newBuilder().setName("Spring").build()
val reply: HelloReply = helloStub.sayHello(request)
println(reply.getMessage())
}
}Netty シェードクライアントトランスポートへの切り替え
内部的には、リモートの gRPC ネットワーク呼び出しは Netty を使用して行われます。spring-boot-starter-grpc-client スターター POM に含まれる Netty のバージョンが、使用している他のライブラリと互換性がない場合は、「シェーディング」バージョンに切り替えることができます。
切り替えるには、io.grpc:grpc-netty を除外して io.grpc:grpc-netty-shaded を含めることができます。例:
Maven
Gradle
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-grpc-client</artifactId>
<exclusions>
<!-- Exclude the gRPC Netty dependency -->
<exclusion>
<groupId>io.grpc</groupId>
<artifactId>grpc-netty</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- Use gRPC Netty Shaded instead -->
<dependency>
<groupId>io.grpc</groupId>
<artifactId>grpc-netty-shaded</artifactId>
</dependency>dependencies {
implementation('org.springframework.boot:spring-boot-starter-grpc-client') {
// Exclude the gRPC Netty dependency
exclude group: 'io.grpc', module: 'grpc-netty'
}
// Use gRPC Netty Shaded instead
implementation "io.grpc:grpc-netty-shaded"
}SSL サポート
クライアントの gRPC アプリケーションは、SSL/TLS 暗号化接続を使用して gRPC サービスに接続できます。gRPC 接続は、標準の一方向 TLS または相互 TLS を使用するように構成できます。
標準的な一方向 TLS
標準の一方向 TLS を使用するには、チャネルプロパティで ssl.enabled プロパティを true に設定します。例: 以下の設定で、myservice チャネルの SSL/TLS 接続が有効になります。
プロパティ
YAML
spring.grpc.client.channel.myservice.target=static://grpc.example.com:9090
spring.grpc.client.channel.myservice.ssl.enabled=truespring:
grpc:
client:
channel:
myservice:
target: static://grpc.example.com:9090
ssl:
enabled: true相互 TLS
相互 TLS(mTLS)は、クライアントとサーバーの両方が互いに証明書を提示する必要があるセキュリティプロトコルです。相互 TLS を使用するには、チャネルプロパティの ssl.bundle プロパティを設定します。SSL バンドルの宣言方法の詳細については、SSL core features documentation を参照してください。
以下は、myservice チャネルが相互 TLS のために mybundle バンドルを使用するように構成する例です。
プロパティ
YAML
spring.grpc.client.channel.myservice.target=static://grpc.example.com:9090
spring.grpc.client.channel.myservice.ssl.bundle=mybundlespring:
grpc:
client:
channel:
myservice:
target: static://grpc.example.com:9090
ssl:
bundle: mybundle たとえばテストを容易にするために、クライアント SSL サポートを一時的に無効にするには、チャネル設定で
|
Using In-Process Channels
You can communicate with an in-process server (i.e. not listening on a network port) by including the io.grpc.grpc-inprocess dependency on your classpath.
In this mode, the in-process channel factory is auto-configured in addition to the regular channel factories (e.g. Netty). To prevent users from having to deal with multiple channel factories, a composite channel factory is configured as the primary channel factory bean. The composite consults its composed factories to find the first one that supports the channel target.
To use the in-process server the channel target must be set to in-process:<name>
To disable the in-process channel factory, you can set the spring.grpc.client.inprocess.enabled property to false. |
可観測性
Spring Boot provides auto-configuration of the ObservationGrpcClientInterceptor (英語) whenever Micrometer is available. This interceptor provides observability into your gRPC client applications.
If you use Micrometer, but prefer to not to use it for gRPC, you can set spring.grpc.client.observation.enabled to false. |
Channel Customization
If you need to customize your gRPC channel beyond the basic properties, you can use a GrpcChannelBuilderCustomizer (Javadoc) . Each customizer is called with the logical target name and the ManagedChannelBuilder (英語) that will build the channel. There’s also a convenient matching(String pattern) factory method that will limit customizations to targets that match the given regex pattern.
A common customizer use-case is to add security interceptors to the builder. For example, here we’re adding the BearerTokenAuthenticationInterceptor (Javadoc) to the target matching “hello”:
Java
Kotlin
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.grpc.client.GrpcChannelBuilderCustomizer;
import org.springframework.grpc.client.interceptor.security.BasicAuthenticationInterceptor;
@Configuration(proxyBeanMethods = false)
public class MyGrpcConfiguration {
@Bean
GrpcChannelBuilderCustomizer<?> helloChannelCustomizer() {
return GrpcChannelBuilderCustomizer.matching("hello",
(builder) -> builder.intercept(new BasicAuthenticationInterceptor("user", "password")));
}
}import io.grpc.ManagedChannelBuilder
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import org.springframework.grpc.client.GrpcChannelBuilderCustomizer
import org.springframework.grpc.client.interceptor.security.BasicAuthenticationInterceptor
import java.util.function.Consumer
@Configuration(proxyBeanMethods = false)
class MyGrpcConfiguration {
@Bean
fun helloChannelCustomizer(): GrpcChannelBuilderCustomizer<*> {
return GrpcChannelBuilderCustomizer.matching("hello", { builder ->
builder.intercept(BasicAuthenticationInterceptor("user", "password"))
})
}
}Testing gRPC Applications
To help test your gRPC client and server applications you can use the spring-boot-grpc-test module or the spring-boot-starter-grpc-client-test / spring-boot-starter-grpc-server-test starter POMs.
Using In-Process Test Transport
The @AutoConfigureTestGrpcTransport (Javadoc) annotation allows you to quickly replace gRPC communication channels with in-process channels specifically designed for testing. Unlike regular in-process channels, these test channels to not require any configuration.
Using test gRPC transport means that you don’t need to actually listen on a network port to start your application. This allows your tests to run quickly, whilst still ensuring that your application works as expected.
By default, using @AutoConfigureTestGrpcTransport (Javadoc) will:
Configure test
GrpcServerFactory(Javadoc) /GrpcChannelFactory(Javadoc) beansDisable any gRPC servelt registration.
Disable
GrpcServerFactory(Javadoc) bean auto-configuration.Disable
GrpcChannelFactory(Javadoc) bean auto-configuration.
The following example shows how you can use @AutoConfigureTestGrpcTransport (Javadoc) to test a gRPC server application:
Java
Kotlin
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.grpc.test.autoconfigure.AutoConfigureTestGrpcTransport;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.grpc.client.ImportGrpcClients;
import static org.assertj.core.api.Assertions.assertThat;
@SpringBootTest
@AutoConfigureTestGrpcTransport
@ImportGrpcClients(types = HelloWorldGrpc.HelloWorldBlockingStub.class)
class MyGrpcTests {
@Autowired
private HelloWorldGrpc.HelloWorldBlockingStub helloStub;
@Test
void sayHello() {
HelloRequest request = HelloRequest.newBuilder().setName("Spring").build();
HelloReply reply = this.helloStub.sayHello(request);
assertThat(reply.getMessage()).isEqualTo("Hello 'Spring'");
}
}import org.assertj.core.api.Assertions.assertThat
import org.jooq.DSLContext
import org.junit.jupiter.api.Test
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.grpc.test.autoconfigure.AutoConfigureTestGrpcTransport
import org.springframework.boot.test.context.SpringBootTest
import org.springframework.grpc.client.ImportGrpcClients
@SpringBootTest
@AutoConfigureTestGrpcTransport
@ImportGrpcClients(types = [HelloWorldGrpc.HelloWorldBlockingStub::class])
class MyGrpcTests(@Autowired val helloStub: HelloWorldGrpc.HelloWorldBlockingStub) {
@Test
fun sayHello() {
val request = HelloRequest.newBuilder().setName("Spring").build()
val reply = helloStub.sayHello(request)
assertThat(reply.getMessage()).isEqualTo("Hello 'Spring'")
}
}実行中のサーバーでのテスト
If you prefer to test your gRPC application by starting the real server and using the actual network connection, we recommend that you use random ports. This will ensure that you can run your tests in any environment, and that you won’t accidentally call real services.
To start a gRPC server using a random port, set spring.grpc.server.port to 0. You can use the @LocalGrpcServerPort (Javadoc) annotation to obtain the actual port that the server started on.
Here’s an example test:
Java
Kotlin
import io.grpc.ManagedChannel;
import io.grpc.netty.NettyChannelBuilder;
import org.junit.jupiter.api.Test;
import org.springframework.boot.docs.io.grpc.testing.localserverport.HelloWorldGrpc.HelloWorldBlockingStub;
import org.springframework.boot.grpc.test.autoconfigure.LocalGrpcServerPort;
import org.springframework.boot.test.context.SpringBootTest;
import static org.assertj.core.api.Assertions.assertThat;
@SpringBootTest(properties = "spring.grpc.server.port=0")
class MyGrpcIntegrationTests {
@LocalGrpcServerPort
private int port;
@Test
void sayHello() {
String target = "localhost:%s".formatted(this.port);
ManagedChannel channel = NettyChannelBuilder.forTarget(target).usePlaintext().build();
try {
HelloWorldBlockingStub hello = HelloWorldGrpc.newBlockingStub(channel);
HelloRequest request = HelloRequest.newBuilder().setName("Spring").build();
assertThat(hello.sayHello(request).getMessage()).isEqualTo("Hello 'Spring'");
}
finally {
channel.shutdown();
}
}
}import io.grpc.ManagedChannel
import io.grpc.netty.NettyChannelBuilder
import org.assertj.core.api.Assertions.assertThat
import org.junit.jupiter.api.Test
import org.springframework.boot.grpc.test.autoconfigure.LocalGrpcServerPort
import org.springframework.boot.test.context.SpringBootTest
@SpringBootTest(properties = ["spring.grpc.server.port=0"])
class MyGrpcIntegrationTests {
@LocalGrpcServerPort
var port = 0
@Test
fun sayHello() {
val target = "localhost:${port}"
val channel: ManagedChannel = NettyChannelBuilder.forTarget(target).usePlaintext().build()
try {
val hello: HelloWorldGrpc.HelloWorldBlockingStub = HelloWorldGrpc.newBlockingStub(channel)
val request = HelloRequest.newBuilder().setName("Spring").build()
assertThat(hello.sayHello(request).getMessage()).isEqualTo("Hello 'Spring'")
} finally {
channel.shutdown()
}
}
}