目的
Spring Boot + kotlin + gRPC でアプリケーションを実装する上で簡易な動作確認ができるようにgrpcurlというツールを使っています.
このツールはプロトコルバッファの記述子ファイルを必要とするため定義ファイルからそれを作成し使用しています.
しかしこれですとプロトコルバッファの定義ファイルが変更されるたび記述子ファイルの更新もしなければならず面倒なためserver reflectionを使い楽をすることにしました.
grpcurlについてはgithubを参照してください.
https://github.com/fullstorydev/grpcurl
server reflectionとは
この記事 を参考にさせていただきました.
サーバーリフレクションはクライアントのコマンドラインからgRPCの定義の取得あるいは実行を可能にするgRPCサーバの拡張機能。サーバーリフレクションによってcurlライクなことがgRPCサーバでも実現できる。
このことからサーバ側からgRPCの定義の提供を受けることで grpcurlが必要としているプロトコルバッファの記述子ファイルがなくても通信ができるようになるようです.
環境
- Spring Boot 2.0.0
- grpc-spring-boot-starter 2.2.0
- kotlin 1.2.20
- gradle 4.5.1
実装
https://github.com/grpc/grpc-java/blob/master/documentation/server-reflection-tutorial.md を参考にします.
build.gradle
必要なパッケージを追加します.
dependencies {
compile "io.grpc:grpc-netty:${grpcVersion}"
compile "io.grpc:grpc-protobuf:${grpcVersion}"
compile "io.grpc:grpc-stub:${grpcVersion}"
+ compile "io.grpc:grpc-services:${grpcVersion}"
compile "org.lognet:grpc-spring-boot-starter:2.2.0"
interceptor
grpc-spring-boot-starterのドキュメント を読むと GRpcServerBuilderConfigurer
を継承したクラスを用意すればいいようです.
package com.yamatomo.sample.grpcInterceptors
import io.grpc.ServerBuilder
import io.grpc.protobuf.services.ProtoReflectionService
import org.lognet.springboot.grpc.GRpcServerBuilderConfigurer
import org.springframework.stereotype.Component
@Component
class BuildConfigure: GRpcServerBuilderConfigurer() {
override fun configure(serverBuilder: ServerBuilder<*>) {
serverBuilder.addService(ProtoReflectionService.newInstance())
}
}
あとは gradle bootRun で起動すればOKです. 記述子ファイルがなくとも grpcurl でレスポンスがうけとれるようになります.
$ grpcurl -plaintext localhost:6565 sample.ExampleService.GetTasks
{
"task": [
{
"id": 1,
"text": "hogehoge"
},
{
"id": 2,
"text": "foobar"
}
]
}
開発環境のみ server reflection が有効になるようにする
あくまで動作確認が目的なので application.properties
に server reflection の On/Off を定義し開発環境のみ有効にするコードにしてみます.
application.properties
grpc.interceptor.useReflection=false
application-development.properties
開発環境用の設定ファイルを用意します.
grpc.interceptor.useReflection=true
データクラス
application.properties
をマッピングするデータクラスを作成します.
package com.yamatomo.sample.grpcInterceptors
import org.springframework.boot.context.properties.ConfigurationProperties
import org.springframework.stereotype.Component
@Component
@ConfigurationProperties(prefix = "grpc.interceptor")
data class InterceptorProperties (
var useReflection: Boolean = false
)
interceptor
先ほど実装したコードにデータクラスから On/Off を判定するように書き換えます.
package com.yamatomo.sample.grpcInterceptors
import io.grpc.ServerBuilder
import io.grpc.protobuf.services.ProtoReflectionService
import org.lognet.springboot.grpc.GRpcServerBuilderConfigurer
+import org.springframework.beans.factory.annotation.Autowired
import org.springframework.stereotype.Component
@Component
class BuildConfigure: GRpcServerBuilderConfigurer() {
+ @Autowired
+ lateinit var properties: InterceptorProperties
override fun configure(serverBuilder: ServerBuilder<*>) {
+ if (!properties.useReflection) return
serverBuilder.addService(ProtoReflectionService.newInstance())
}
}
bootRunのオプションでprofileをdevelopmentと指定して起動します.
$ gradlew bootRun -Dspring.profiles.active=development
まとめ
気軽に動作確認ができるのは大きいと思いました.
要件によっては grpc-gateway
を導入しないケースでも動作確認のためだけに導入するといったことも減らせるのではないかなと思います.