2. 概述

gRPC 是一个高性能、开源的 RPC 框架,最初由 Google 开发。它能有效消除样板代码,轻松连接跨数据中心的异构服务。

框架基于客户端-服务器模型的远程过程调用实现。客户端应用可以直接调用服务器应用的方法,就像调用本地对象一样简单

本文将通过以下步骤创建典型的 gRPC 客户端-服务器应用:

  1. .proto 文件中定义服务
  2. 使用协议缓冲编译器生成服务器和客户端代码
  3. 创建服务器应用,实现生成的服务接口并启动 gRPC 服务器
  4. 创建客户端应用,使用生成的桩进行 RPC 调用

我们将实现一个简单的 HelloService,通过传入姓名返回问候语。

3. Maven 依赖

添加以下核心依赖:

<dependency>
    <groupId>io.grpc</groupId>
    <artifactId>grpc-netty</artifactId>
    <version>1.62.2</version>
</dependency>
<dependency>
    <groupId>io.grpc</groupId>
    <artifactId>grpc-protobuf</artifactId>
    <version>1.62.2</version>
</dependency>
<dependency>
    <groupId>io.grpc</groupId>
    <artifactId>grpc-stub</artifactId>
    <version>1.62.2</version>
</dependency>

4. 定义服务

核心是定义可远程调用的方法及其参数和返回类型,通过协议缓冲(Protocol Buffers)在 .proto 文件中完成,同时描述消息结构。

4.1 基础配置

创建 HelloService.proto 文件,添加基础配置:

syntax = "proto3";
option java_multiple_files = true;
package org.baeldung.grpc;
  • syntax = "proto3":指定语法版本
  • java_multiple_files = true:生成独立 Java 文件(默认单文件)
  • package:指定生成类的 Java 包名

4.2 定义消息结构

定义请求消息:

message HelloRequest {
    string firstName = 1;
    string lastName = 2;
}

⚠️ 关键点

  • 每个属性需分配唯一标签(如 = 1
  • 协议缓冲用标签而非属性名表示字段(比 JSON 更高效)
  • 响应消息同理:
message HelloResponse {
    string greeting = 1;
}

4.3 定义服务契约

定义服务接口:

service HelloService {
    rpc hello(HelloRequest) returns (HelloResponse);
}

✅ 支持多种调用模式:

  • 一元请求/响应(如示例)
  • 流式调用:在参数/返回值前加 stream 关键字

5. 生成代码

.proto 文件传递给协议缓冲编译器 protoc 生成 Java 代码,有两种方式:

5.1 使用协议缓冲编译器

操作步骤

  1. 下载 Protocol Buffer 编译器
  2. 获取 gRPC Java 代码生成插件
  3. 执行命令:
protoc --plugin=protoc-gen-grpc-java=$PATH_TO_PLUGIN -I=$SRC_DIR \
  --java_out=$DST_DIR --grpc-java_out=$DST_DIR $SRC_DIR/HelloService.proto

5.2 使用 Maven 插件(推荐)

集成到构建流程更高效:

<build>
  <extensions>
    <extension>
      <groupId>kr.motd.maven</groupId>
      <artifactId>os-maven-plugin</artifactId>
      <version>1.6.1</version>
    </extension>
  </extensions>
  <plugins>
    <plugin>
      <groupId>org.xolstice.maven.plugins</groupId>
      <artifactId>protobuf-maven-plugin</artifactId>
      <version>0.6.1</version>
      <configuration>
        <protocArtifact>
          com.google.protobuf:protoc:3.3.0:exe:${os.detected.classifier}
        </protocArtifact>
        <pluginId>grpc-java</pluginId>
        <pluginArtifact>
          io.grpc:protoc-gen-grpc-java:1.4.0:exe:${os.detected.classifier}
        </pluginArtifact>
      </configuration>
      <executions>
        <execution>
          <goals>
            <goal>compile</goal>
            <goal>compile-custom</goal>
          </goals>
        </execution>
      </executions>
    </plugin>
  </plugins>
</build>

os-maven-plugin 自动检测平台类型(如 ${os.detected.classifier}

6. 创建服务器

代码生成后,关键文件包括:

  • HelloRequest.java:请求类型定义
  • HelloResponse.java:响应类型定义
  • HelloServiceImplBase.java:服务抽象基类

6.1 重写服务基类

**默认实现会抛出 StatusRuntimeException**(表示方法未实现),需继承并重写:

public class HelloServiceImpl extends HelloServiceImplBase {

    @Override
    public void hello(
      HelloRequest request, StreamObserver<HelloResponse> responseObserver) {

        String greeting = new StringBuilder()
          .append("Hello, ")
          .append(request.getFirstName())
          .append(" ")
          .append(request.getLastName())
          .toString();

        HelloResponse response = HelloResponse.newBuilder()
          .setGreeting(greeting)
          .build();

        responseObserver.onNext(response);
        responseObserver.onCompleted();
    }
}

⚠️ 关键细节

  • 方法签名与 .proto 定义不同:不直接返回 HelloResponse,而是通过 StreamObserver 回调
  • 支持阻塞/非阻塞调用:客户端可自由选择
  • 必须调用 onCompleted():否则连接会挂起,客户端无限等待

6.2 启动 gRPC 服务器

public class GrpcServer {
    public static void main(String[] args) throws Exception {
        Server server = ServerBuilder
          .forPort(8080)
          .addService(new HelloServiceImpl())
          .build();

        server.start();
        server.awaitTermination();
    }
}

✅ 简单粗暴:

  • ServerBuilder 创建服务器并绑定端口
  • addService() 注册服务实现
  • awaitTermination() 保持前台运行(阻塞主线程)

7. 创建客户端

gRPC 通过 Channel 抽象底层细节(连接管理、负载均衡等):

public class GrpcClient {
    public static void main(String[] args) throws Exception {
        ManagedChannel channel = ManagedChannelBuilder.forAddress("localhost", 8080)
          .usePlaintext() // 明文传输(生产环境应使用 TLS)
          .build();

        // 创建阻塞式桩
        HelloServiceGrpc.HelloServiceBlockingStub stub 
          = HelloServiceGrpc.newBlockingStub(channel);

        HelloResponse helloResponse = stub.hello(HelloRequest.newBuilder()
          .setFirstName("Baeldung")
          .setLastName("gRPC")
          .build());

        System.out.println(helloResponse.getGreeting());
        channel.shutdown();
    }
}

🔍 核心概念

  • 桩(Stub):客户端与服务器交互的主入口
  • 桩类型
    • 阻塞桩(示例):同步等待响应
    • 非阻塞桩:异步调用(需额外处理回调)
  • 消息构建:使用自动生成的 Builder 创建请求对象

8. 总结

本文展示了如何通过 gRPC 简化服务间通信开发:

  1. 专注服务定义.proto 文件描述接口
  2. 自动生成代码:消除样板代码
  3. 多语言支持:轻松连接异构系统

完整代码示例见 GitHub 仓库


原始标题:Introduction to gRPC | Baeldung