TL;DR 本教程帶你用 Spring Boot 快速搭建一個可運行的 gRPC 服務與客户端示例,包含:proto 定義、構建生成 Java stub、服務端實現、客户端調用、配置説明與常見坑和最佳實踐。示例同時給出 Maven 配置(也會提到 Gradle 思路),推薦使用社區成熟的 grpc-spring-boot-starter 簡化集成(也提供手工方式的關鍵點)。
1. 前置條件
- Java 11+(根據項目需要,也可用 Java 8/17)
- Maven 或 Gradle 構建工具(以下示例以 Maven 為主)
- protoc(可通過 Maven/Gradle 插件自動下載,不必須本機已安裝)
- 熟悉 Spring Boot 基礎項目結構
2. 選擇集成方式(兩條常用路線)
- 使用社區 starter(推薦):
net.devh:grpc-spring-boot-starter類庫(或其拆分後的 server/client starter)能把 gRPC 服務以 Spring Bean 形式暴露,支持註解、配置化、攔截器、健康檢查等,省去大量樣板代碼。 - 手工集成:獨立使用
io.grpc原生 API(ServerBuilder、ManagedChannel)並把它們以 Spring Bean 管理。這種方式更底層但更靈活。
下面以 starter + Maven 的方式給出完整示例,並補充手工集成的關鍵點。
3. 項目結構(示例)
springboot-grpc/
├─ src/
│ ├─ main/
│ │ ├─ java/
│ │ │ └─ com.example.grpc/
│ │ │ ├─ GrpcServerApplication.java
│ │ │ ├─ service/
│ │ │ │ └─ GreetingServiceImpl.java
│ │ │ └─ client/
│ │ │ └─ GrpcClientRunner.java
│ │ └─ proto/
│ │ └─ greeter.proto
├─ pom.xml
4. 定義 proto(src/main/proto/greeter.proto)
syntax = "proto3";
package com.example.grpc;
option java_package = "com.example.grpc.proto";
option java_outer_classname = "GreeterProto";
service Greeter {
rpc SayHello (HelloRequest) returns (HelloReply);
}
message HelloRequest {
string name = 1;
}
message HelloReply {
string message = 1;
}
説明:java_package 與 java_outer_classname 可控制生成 Java 包名和類名,便於項目結構組織。
5. Maven 配置(關鍵依賴與插件)
下面的 pom.xml 給出核心依賴和 protobuf / gRPC 生成配置(示例中採用 Maven protobuf 插件自動下載 protoc 和 grpc 插件並生成代碼),同時加入 grpc-spring-boot-starter(示例使用 net.devh 風格,具體版本請根據你環境選擇最新穩定版)。
<!-- 省略常規的 parent 和 properties -->
<project ...>
<modelVersion>4.0.0</modelVersion>
<properties>
<java.version>17</java.version>
<spring.boot.version>3.1.0</spring.boot.version>
<grpc.version>1.56.0</grpc.version> <!-- 請按需更新 -->
<protobuf.version>3.24.0</protobuf.version>
<protoc-gen-grpc-java.version>1.56.0</protoc-gen-grpc-java.version>
</properties>
<dependencies>
<!-- Spring Boot -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<!-- grpc starter (server + client support) - 用於示例 -->
<dependency>
<groupId>net.devh</groupId>
<artifactId>grpc-spring-boot-starter</artifactId>
<version>2.13.1.RELEASE</version>
</dependency>
<!-- gRPC runtime (如果需要手工方式) -->
<dependency>
<groupId>io.grpc</groupId>
<artifactId>grpc-stub</artifactId>
<version>${grpc.version}</version>
</dependency>
<!-- protobuf runtime -->
<dependency>
<groupId>com.google.protobuf</groupId>
<artifactId>protobuf-java</artifactId>
<version>${protobuf.version}</version>
</dependency>
<!-- 可選:反射用於調試 / grpcurl 支持 -->
<dependency>
<groupId>io.grpc</groupId>
<artifactId>grpc-services</artifactId>
<version>${grpc.version}</version>
</dependency>
</dependencies>
<build>
<extensions>
<extension>
<groupId>kr.motd.maven</groupId>
<artifactId>os-maven-plugin</artifactId>
<version>1.7.0</version>
</extension>
</extensions>
<plugins>
<!-- protobuf plugin: 生成 proto -> java -->
<plugin>
<groupId>org.xolstice.maven.plugins</groupId>
<artifactId>protobuf-maven-plugin</artifactId>
<version>0.6.1</version>
<configuration>
<protocArtifact>com.google.protobuf:protoc:${protobuf.version}:exe:${os.detected.classifier}</protocArtifact>
<pluginId>grpc-java</pluginId>
<pluginArtifact>io.grpc:protoc-gen-grpc-java:${protoc-gen-grpc-java.version}:exe:${os.detected.classifier}</pluginArtifact>
</configuration>
<executions>
<execution>
<goals>
<goal>compile</goal>
<goal>compile-custom</goal>
</goals>
</execution>
</executions>
</plugin>
<!-- 其它常規插件(compiler, spring-boot-maven-plugin) -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.10.1</version>
<configuration>
<source>${java.version}</source>
<target>${java.version}</target>
</configuration>
</plugin>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>${spring.boot.version}</version>
</plugin>
</plugins>
</build>
</project>
注:版本號會隨時間更新,上面只是示例。若你使用 Gradle,可使用
com.google.protobufgradle 插件與protoc、protoc-gen-grpc-java相似配置來生成代碼。
6. 生成代碼與編譯
在項目根目錄運行:
mvn clean package
protobuf-maven-plugin 會把 src/main/proto 下的 .proto 文件生成到 target/generated-sources,並被編譯進你的項目。生成的類通常包含 GreeterGrpc(服務接口 stub)和消息 POJO 類(例如 HelloRequest, HelloReply)。
7. 服務端實現(使用 starter)
net.devh starter 允許把實現 Bean 用 @GrpcService 暴露。示例實現 GreetingServiceImpl:
package com.example.grpc.service;
import com.example.grpc.proto.GreeterGrpc;
import com.example.grpc.proto.GreeterProto;
import io.grpc.stub.StreamObserver;
import net.devh.boot.grpc.server.service.GrpcService;
@GrpcService
public class GreetingServiceImpl extends GreeterGrpc.GreeterImplBase {
@Override
public void sayHello(GreeterProto.HelloRequest request, StreamObserver<GreeterProto.HelloReply> responseObserver) {
String name = request.getName();
String msg = "Hello, " + (name.isEmpty() ? "world" : name) + "!";
GreeterProto.HelloReply reply = GreeterProto.HelloReply.newBuilder()
.setMessage(msg)
.build();
responseObserver.onNext(reply);
responseObserver.onCompleted();
}
}
Spring Boot 啓動類:
package com.example.grpc;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class GrpcServerApplication {
public static void main(String[] args) {
SpringApplication.run(GrpcServerApplication.class, args);
}
}
配置(application.yml 或 application.properties):
grpc:
server:
port: 9090 # gRPC 服務監聽端口
enable-reflection: true # 開啓服務反射,方便 grpcurl 等工具調試
8. 客户端調用(兩種方式)
方式 A — 使用 starter 的 @GrpcClient(更 Spring 化)
package com.example.grpc.client;
import com.example.grpc.proto.GreeterGrpc;
import com.example.grpc.proto.GreeterProto;
import net.devh.boot.grpc.client.inject.GrpcClient;
import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;
@Component
public class GrpcClientRunner implements CommandLineRunner {
@GrpcClient("localGrpc")
private GreeterGrpc.GreeterBlockingStub greeterBlockingStub;
@Override
public void run(String... args) throws Exception {
GreeterProto.HelloRequest req = GreeterProto.HelloRequest.newBuilder().setName("Mir").build();
GreeterProto.HelloReply resp = greeterBlockingStub.sayHello(req);
System.out.println("gRPC response: " + resp.getMessage());
}
}
並在 application.yml 裏配置客户端目標:
grpc:
client:
localGrpc:
address: static://localhost:9090
方式 B — 原生 gRPC ManagedChannel
ManagedChannel channel = ManagedChannelBuilder.forAddress("localhost", 9090)
.usePlaintext()
.build();
GreeterGrpc.GreeterBlockingStub stub = GreeterGrpc.newBlockingStub(channel);
HelloReply reply = stub.sayHello(HelloRequest.newBuilder().setName("Mir").build());
channel.shutdown();
9. 調試與測試
- 使用
grpcurl:grpcurl -plaintext localhost:9090 list/grpcurl -plaintext -d '{"name":"Mir"}' localhost:9090 com.example.grpc.Greeter/SayHello(如果啓用反射則更方便) - 用 Java 客户端或集成測試直接調用(如上
GrpcClientRunner) - 開啓日誌
io.grpc包的日誌級別便於排查
10. TLS、認證與攔截器
- TLS:在生產環境強烈建議啓用 TLS(
ServerBuilder.useTransportSecurity(certChainFile, privateKeyFile)或 starter 提供的配置選項)。 - 認證:可以在 gRPC 層添加服務器/客户端攔截器(
ServerInterceptor/ClientInterceptor)做 token 驗證、限流、審計等。starter 支持以 Spring 管理的 interceptor 注入。 - 攔截器示例(ServerInterceptor):
public class AuthInterceptor implements ServerInterceptor {
@Override
public <ReqT, RespT> ServerCall.Listener<ReqT> interceptCall(
ServerCall<ReqT, RespT> call, Metadata headers, ServerCallHandler<ReqT, RespT> next) {
String token = headers.get(Metadata.Key.of("authorization", Metadata.ASCII_STRING_MARSHALLER));
if (!valid(token)) {
call.close(Status.UNAUTHENTICATED.withDescription("Invalid token"), new Metadata());
return new ServerCall.Listener<ReqT>() {};
}
return next.startCall(call, headers);
}
}
11. 常見問題與解決方案(常見坑)
- 生成類找不到 / package 混亂:檢查 proto 中的
option java_package與構建插件輸出路徑,使用mvn clean後重編譯。 - 端口衝突 / 服務未啓動:確認 gRPC 端口配置(與 Spring MVC 端口不同),及是否有防火牆阻止。
- 客户端連接報 UNAVAILABLE:通常是服務未啓動或網絡問題;檢查服務端日誌、端口監聽、
usePlaintext()(測試環境)或 TLS 設置。 - 版本不兼容:gRPC、protobuf、protoc 的版本需配套(如果使用插件自動下載通常安全)。
- Spring Boot 熱重載(devtools)與生成代碼:若使用 IDE 熱重載,確保 generated-sources 被 IDE 識別,或在更改 proto 後重新執行構建任務。
12. 最佳實踐
- 使用 proto 文件作為 API 的唯一事實源(source of truth),並把它放到單獨模塊以便共享(service / client 多項目共享)。
- 對外接口採用語義化版本管理(proto package + major version 例如
com.example.grpc.v1),避免破壞兼容。 - 在生產開啓 TLS,並設計好認證/鑑權方案(mTLS 或 token + interceptors)。
- 使用健康檢查與監控(將 gRPC 服務狀態暴露給 Prometheus / k8s readiness probe)。
- 在負載較高場景配置合適的線程池、流控與 keepalive 策略。
- 使用攔截器統一實現日誌、鑑權與限流策略,方便統一管理。
13. 進階主題(推薦後續擴展)
- 雙向流(bi-directional streaming)與流控(flow control)策略
- gRPC + HTTP/JSON 網關(grpc-gateway)供瀏覽器/外部系統訪問
- 在 Kubernetes 中使用 gRPC 負載均衡(DNS、Envoy/L4)和健康探測
- 使用 protobuf 的
oneof、map與性能優化(避免過大消息)
14. 完整示例回顧(快速複製)
src/main/proto/greeter.proto(見第4節)- Maven
pom.xml(見第5節) - 服務實現
GreetingServiceImpl(見第7節) - 客户端
GrpcClientRunner(見第8節 A) - 配置
application.yml:
server:
port: 8080
grpc:
server:
port: 9090
enable-reflection: true
client:
localGrpc:
address: static://localhost:9090
運行 mvn spring-boot:run,觀察控制枱;或 mvn clean package 生成 jar 後運行。
15. 小結
通過本文你應能搭建一個從 proto 到可運行的 Spring Boot + gRPC 的完整流程:定義 proto → 通過插件生成 Java stub → 使用 grpc-spring-boot-starter 把服務以 Spring Bean 暴露 → 使用 @GrpcClient 或原生 ManagedChannel 調用。starter 大幅減少樣板代碼,推薦在短時間內快速搭建服務;生產環境注意啓用 TLS、攔截器與監控。