2. 概述
gRPC 是一个高性能、开源的 RPC 框架,最初由 Google 开发。它能有效消除样板代码,轻松连接跨数据中心的异构服务。
框架基于客户端-服务器模型的远程过程调用实现。客户端应用可以直接调用服务器应用的方法,就像调用本地对象一样简单。
本文将通过以下步骤创建典型的 gRPC 客户端-服务器应用:
- 在
.proto
文件中定义服务 - 使用协议缓冲编译器生成服务器和客户端代码
- 创建服务器应用,实现生成的服务接口并启动 gRPC 服务器
- 创建客户端应用,使用生成的桩进行 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 使用协议缓冲编译器
操作步骤:
- 下载 Protocol Buffer 编译器
- 获取 gRPC Java 代码生成插件
- 执行命令:
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 简化服务间通信开发:
- ✅ 专注服务定义:
.proto
文件描述接口 - ✅ 自动生成代码:消除样板代码
- ✅ 多语言支持:轻松连接异构系统
完整代码示例见 GitHub 仓库