知識庫 / Spring / Spring Boot RSS 訂閱

Spring Boot 中 gRPC 入門指南

Spring Boot
HongKong
9
11:18 AM · Dec 06 ,2025

1. 概述

gRPC 是一個高性能、開源的 RPC 框架,最初由 Google 開發。 它有助於消除冗餘代碼並連接異構服務,無論是在同一數據中心還是跨數據中心。 該 API 基於 Protocol Buffers,提供 protoc 編譯器,用於為不同的 支持的語言 生成代碼。

我們可以將 gRPC 視為 REST、SOAP 或 GraphQL 的替代方案,它建立在 HTTP/2 之上,利用多路複用或流式連接等功能。

在本教程中,我們將學習如何使用 Spring Boot 實現 gRPC 服務提供者和消費者。

2. 挑戰

首先,我們注意到 Spring Boot 不直接支持 gRPC。 僅支持 Protocol Buffers,這允許我們實現基於 Protocol Buffers 的 REST 服務。 因此,我們需要通過使用第三方庫或自行解決一些挑戰來引入 gRPC:

3. 示例項目

幸運的是,我們還可以使用第三方 Spring Boot Starter 來幫助我們應對挑戰,例如來自 LogNet 的 Starter,或者 gRPC 生態項目。這兩個 Starter 易於集成,但後者同時提供 Provider 和 Consumer 支持,以及許多其他 集成功能,因此我們選擇它作為我們的示例。

在這個示例中,我們設計了一個簡單的 HelloWorld API,並使用一個包含單個 Proto 文件的示例:

syntax = "proto3";

option java_package = "com.baeldung.helloworld.stubs";
option java_multiple_files = true;

message HelloWorldRequest {
    // a name to greet, default is "World"
    optional string name = 1;
}

message HelloWorldResponse {
    string greeting = 1;
}

service HelloWorldService {
    rpc SayHello(stream HelloWorldRequest) returns (stream HelloWorldResponse);
}

如我們所見,我們使用雙向流式傳輸功能。

3.1. gRPC 樁

由於樁對提供者和消費者都是相同的,因此我們在一個與 Spring 獨立的項目中生成它們。 這樣做具有優勢,即該項目的生命週期,包括 protoc 編譯器配置和 Java EE 註解對 Java 依賴項的定義,可以與 Spring Boot 項目的生命週期隔離。

3.2. 服務提供者

實現服務提供者非常簡單。首先,我們需要添加啓動器和我們的樁項目所需的依賴項:

<dependency>
    <groupId>net.devh</groupId>
    <artifactId>grpc-server-spring-boot-starter</artifactId>
    <version>3.1.0.RELEASE</version>
</dependency>
<dependency>
    <groupId>com.baeldung.spring-boot-modules</groupId>
    <artifactId>helloworld-grpc-java</artifactId>
    <version>1.0.0-SNAPSHOT</version>
</dependency>

不需要包含 Spring MVC 或 WebFlux,因為 starter 依賴自帶了陰影 Netty 服務器。我們可以通過在 application.yml 中進行配置,例如配置服務器端口:

grpc:
  server:
    port: 9090

然後,我們需要實現該服務並使用 @GrpcService 註解進行標記。

@GrpcService
public class HelloWorldController extends HelloWorldServiceGrpc.HelloWorldServiceImplBase {

    @Override
    public StreamObserver<HelloWorldRequest> sayHello(
        StreamObserver<HelloWorldResponse> responseObserver
    ) {
        // ...
    }
}

3.3. 服務消費者

對於服務消費者,我們需要將依賴項添加到啓動器和樁(stub)中:

<dependency>
    <groupId>net.devh</groupId>
    <artifactId>grpc-client-spring-boot-starter</artifactId>
    <version>3.1.0.RELEASE</version>
</dependency>
<dependency>
    <groupId>com.baeldung.spring-boot-modules</groupId>
    <artifactId>helloworld-grpc-java</artifactId>
    <version>1.0.0-SNAPSHOT</version>
</dependency>

然後,我們將在 application.yml配置與服務的連接

grpc:
  client:
    hello:
      address: localhost:9090
      negotiation-type: plaintext

名稱 “hello” 是一個自定義的名稱。 這樣,我們就可以配置多個連接,並在將 gRPC 客户端注入到我們的 Spring 組件時,使用此名稱。

@GrpcClient("hello")
HelloWorldServiceGrpc.HelloWorldServiceStub stub;

4. 潛在問題

實施和消費使用 Spring Boot 的 gRPC 服務相對簡單。但是,我們應該意識到一些潛在問題。

4.1. SSL握手

將數據通過HTTP傳輸意味着在不使用SSL的情況下,信息將未加密發送。 集成的Netty服務器默認不使用SSL,因此需要顯式配置。

否則,對於本地測試,我們可以保持連接未加密。在這種情況下,需要配置消費者,如之前所示:

grpc:
  client:
    hello:
      negotiation-type: plaintext

消費者的默認設置是使用 TLS,而提供者的默認設置是跳過 SSL 加密。因此,消費者和提供者的默認設置不一致。

4.2. 不使用 @Autowired 的消費者注入

我們通過將客户端對象注入到 Spring 組件中來實現消費者:

@GrpcClient("hello")
HelloWorldServiceGrpc.HelloWorldServiceStub stub;

這通過一個 BeanPostProcessor 實現,並且作為對 Spring 內置依賴注入機制的補充而工作。這意味着我們不能同時使用 @GrpcClient 註解與 @Autowired 或構造器注入一起使用。相反,我們只能使用字段注入。

只能通過使用配置類來分離注入:

@Configuration
public class HelloWorldGrpcClientConfiguration {

    @GrpcClient("hello")
    HelloWorldServiceGrpc.HelloWorldServiceStub helloWorldClient;

    @Bean
    MyHelloWorldClient helloWorldClient() {
      return new MyHelloWorldClient(helloWorldClient);
    }
}

4.3. 映射傳輸對象

使用 protoc 生成的數據類型在調用帶有 null 值的 setter 方法時可能會失敗:

public HelloWorldResponse map(HelloWorldMessage message) {
    return HelloWorldResponse
      .newBuilder()
      .setGreeting( message.getGreeting() ) // might be null
      .build();
}

因此,在調用設置器之前,我們需要進行空值檢查。當我們使用映射框架時,需要配置映射器生成器以執行此類空值檢查。例如,一個 MapStruct 映射器需要一些特殊配置:

@Mapper(
  componentModel = "spring",
  nullValuePropertyMappingStrategy = NullValuePropertyMappingStrategy.IGNORE,
  nullValueCheckStrategy = NullValueCheckStrategy.ALWAYS
)
public interface HelloWorldMapper {
    HelloWorldResponse map(HelloWorldMessage message);
}

4.4. 測試

啓動器不提供任何專門的支持來實施測試。 即使 grpc-java 項目也僅提供對 JUnit 4 的最小支持,並且不支持 JUnit 5。

4.5. 本地圖像

當我們需要構建本地圖像時,目前 gRPC 尚不提供支持。由於客户端注入是通過反射實現的,因此這需要額外的配置才能正常工作

5. 結論

在本文中,我們瞭解到可以將 gRPC 提供程序和消費者輕鬆地集成到我們的 Spring Boot 應用程序中。 然而,需要注意的是,這也會帶來一些限制,例如缺乏對測試和原生鏡像的支持。

user avatar
0 位用戶收藏了這個故事!
收藏

發佈 評論

Some HTML is okay.