SpringBootでgRPCの初期設定を行った際のメモ
build.gradle
// プラグイン追加
apply plugin: 'com.google.protobuf'
// 下記追加
protobuf {
protoc {
artifact = "com.google.protobuf:protoc:3.10.0"
}
plugins {
grpc {
artifact = 'io.grpc:protoc-gen-grpc-java:1.4.0'
}
}
generateProtoTasks {
all()*.plugins {
grpc {}
}
}
}
sourceSets {
main {
java {
srcDirs 'build/generated/source/proto/main/grpc'
srcDirs 'build/generated/source/proto/main/java'
}
}
}
dependencies {
implementation('io.github.lognet:grpc-spring-boot-starter:3.4.1')
}
proto作成
Company.proto
syntax = "proto3";
option java_multiple_files = true;
option java_package = "com.hira.test.grpc";
option java_outer_classname = "CompanyProto";
package company;
// サービスメソッド定義
service Company {
// 取得
rpc Find (CompanyFindRequest) returns (CompanyFindReply);
// 登録
rpc Create (CompanyCreateRequest) returns (CompanyCreateReply);
// 更新
rpc Update (CompanyUpdateRequest) returns (CompanyUpdateReply);
// 削除
rpc Delete (CompanyDeleteRequest) returns (CompanyDeleteReply);
}
// 会社
message Company {
// ID
int32 id = 1;
// 会社名
string name = 2;
// 住所
string address = 3;
// 電場番号
string tel = 4;
}
// 付属情報
message Option {
// 登録日時
string createDt = 1;
// 登録ユーザー
string createUser = 2;
// 更新日時
string updateDt = 1;
// 更新ユーザー
string updateUser = 2;
}
// 取得リクエスト定義
message CompanyFindRequest{
string id= 1;
}
// 取得レスポンス定義
message CompanyFindReply {
Company company = 1;
Option option = 2;
}
・・・(略)
Protoファイルをクライアントサイドとサーバサイドそれぞれでソース自動生成を行う。
GradleのgenerateProtoコマンドを実行するとbuild/generated/source/proto/main/配下に必要なソースが自動生成される。
サーバサイドの実装
CompanyGrpcService.java
@GRpcService
public class CompanyGrpcService extends CompanyServiceGrpc.CompanyServiceImplBase {
// 会社リポジトリ
@Autowired
CompanyRepository companyRepository;
/**
* 会社取得.
*/
@Override
public void find(CompanyFindRequest request, StreamObserver<CompanyFindReply> responseObserver) {
try {
// 会社取ID
Company company = companyRepository.find(request.getId());
CompanyFindReply.Builder builder = CompanyFindReply.newBuilder();
if (company == null) {
responseObserver.onError(new StatusException(Status.NOT_FOUND));
} else {
Company.Builder companyBuilder = builder.getCompanyBuilder();
Option.Builder optionBuilder = builder.getOptionBuilder();
companyBuilder.setId(company.getId());
companyBuilder.setName(company.getName());
builder.setPartnerCompany(partnerCompanyBuilder);
builder.setOption(optionBuilder);
responseObserver.onNext(builder.build());
responseObserver.onCompleted();
}
} catch(Exception e) {
StatusRuntimeException exception = Status.INTERNAL
.withDescription(e.getMessage())
.withCause(e)
.asRuntimeException();
responseObserver.onError(exception);
}
}
クライアント(呼び出し)の実装
接続先のホストとポートを設定
application.properties
app.grpc.test.url=xxx.xxx.xxx.xxx
app.grpc.test.port=xxxx
AppConfig.java
@Component
@ConfigurationProperties(prefix = "app")
@Data
public class AppConfig {
private Map<String, String> grpc;
}
ManagedChannelは、予め初期化しておいて呼び出す。
GrpcConfig.java
@Component
@Data
public class GrpcConfig {
@Autowired
AppConfig config;
private ManagedChannel channelTest;
@PostConstruct
void initGrpcManagedChannel() {
channelTest = ManagedChannelBuilder
.forAddress(
config.getGrpc().get("test.url"),
Integer.parseInt(config.getGrpc().get("test.port")))
.usePlaintext(true)
.build();
}
}
CompanyMaintenanceService.java
@service
public class CompanyMaintenanceService {
@Autowired
GrpcConfig grpcConfig;
public Company find(int id) {
ManagedChannel channel = grpcConfig.getChannelTest();
CompanyServiceGrpc.CompanyServiceBlockingStub stub = CompanyServiceGrpc.newBlockingStub(channel);
// リクエスト作成
CompanyFindRequest request =
CompanyFindRequest.newBuilder()
.setId(id)
.build();
try {
// リクエスト実行
CompanyFindReply reply = stub.find(request);
// 結果取得
Company company = reply.getCompany();
Option option = reply.getOption();
・・・(略)
} catch (StatusRuntimeException e) {
if(Status.NOT_FOUND.getCode() == e.getStatus().getCode()) {
// 404の処理
}
}
}
}
Protoのドキュメント化
protoc-gen-docを利用してProtoファイルからHTMLドキュメントを生成
protoc.exe --doc_out=html,index.html:doc proto/*.proto
所感
リクエストとレスポンスのパラメータ情報の定義の簡単さや、protoファイルによる定義でソースやドキュメントを自動出力できるためクライアントとサーバの定義共有が容易。