日常接口开发绝大多数团队还在用 RESTful HTTP 接口,看似简单,但高并发内部服务通信存在天然短板:JSON 报文冗余、序列化性能差、HTTP 头部体积大、无内置双向流、长轮询实时推送实现复杂、超时重试、负载均衡、拦截器统一封装成本高。
gRPC 基于 HTTP/2 + Protobuf 二进制序列化,天生具备更小报文、更快序列化、双向流式通信、内置拦截器、原生负载均衡、多语言兼容、代码自动生成等优势,微服务内部调用性能远超 REST。
很多开发者误以为 gRPC 配置繁琐、学习成本高、Protobuf 语法难上手,Spring Boot 4.0 配套 yidongnan/grpc-spring-boot-starter 大幅简化接入,仅需4步即可完成服务端+客户端完整通信,零复杂原生配置,上手难度低于传统 REST。
一、gRPC vs REST 对比
1. 传输与序列化
-
1. REST:文本JSON,键名重复占用大量带宽,序列化/反序列化CPU消耗高; -
2. gRPC:Protobuf 二进制编码,无冗余字段,体积缩减30%~70%,编解码速度提升数倍。
2. 底层协议
-
1. REST:HTTP/1.1,单请求单连接,头部臃肿,不支持长连接多路复用; -
2. gRPC:HTTP/2 多路复用,单连接并发多请求,支持双向流、服务端流、客户端流。
3. 代码生成
-
1. REST:手动写DTO、Controller、接口文档,重复代码多; -
2. gRPC:编写 .proto文件,Maven插件自动生成服务、入参、出参实体,杜绝参数不一致问题。
4. 内置能力
REST 需要自行封装:拦截器、超时、重试、负载均衡、限流;
gRPC 原生支持:拦截器、超时控制、重试策略、多种负载均衡、元数据传递、双向流。
5. 适用场景
REST:对外开放接口、前端页面交互;
gRPC:微服务内部RPC调用、大数据流式传输、实时消息推送、高并发内网通信。
二、整体环境说明
-
• Spring Boot:4.0.x -
• grpc-spring-boot-starter:2.15.0(适配SpringBoot4) -
• Protobuf:3.25.x -
• 构建工具:Maven -
• 两套工程:grpc-server(服务提供方)、grpc-client(调用方)
三、第一步:统一Maven父依赖与Protobuf编译插件
父pom统一版本管理
<properties>
<spring.boot.version>4.0.0</spring.boot.version>
<grpc.version>1.64.0</grpc.version>
<grpc.starter.version>2.15.0</grpc.starter.version>
<protobuf.version>3.25.3</protobuf.version>
</properties>
<dependencyManagement>
<dependencies>
<!-- SpringBoot 4 父工程 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>${spring.boot.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<!-- gRPC 统一版本 -->
<dependency>
<groupId>net.devh</groupId>
<artifactId>grpc-spring-boot-starter</artifactId>
<version>${grpc.starter.version}</version>
</dependency>
</dependencies>
</dependencyManagement>
服务端/客户端通用pom依赖
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<!-- gRPC 核心starter,自动装配,无需手动管理Netty、grpc原生依赖 -->
<dependency>
<groupId>net.devh</groupId>
<artifactId>grpc-spring-boot-starter</artifactId>
</dependency>
</dependencies>
<build>
<extensions>
<extension>
<groupId>kr.motd.maven</groupId>
<artifactId>os-maven-plugin</artifactId>
<version>1.7.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:${protobuf.version}:exe:${osdetector.classifier}</protocArtifact>
<pluginId>grpc-java</pluginId>
<pluginArtifact>io.grpc:protoc-gen-grpc-java:${grpc.version}:exe:${osdetector.classifier}</pluginArtifact>
<!-- proto文件存放目录 -->
<protoSourceRoot>${project.basedir}/src/main/proto</protoSourceRoot>
</configuration>
<executions>
<execution>
<goals>
<goal>compile</goal>
<goal>compile-custom</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
四、第二步:编写Protobuf接口定义文件
在 src/main/proto 新建 user.proto,统一定义请求、响应、RPC方法,服务端客户端共用同一份契约,杜绝参数不一致。
syntax = "proto3";
package com.grpc.user;
// 自动生成代码包路径
option java_multiple_files = true;
option java_package = "com.grpc.user.api";
option java_outer_classname = "UserProto";
option objc_class_prefix = "USER";
// 请求体
message UserQueryReq {
int64 userId = 1;
string userName = 2;
}
// 响应体
message UserQueryResp {
int64 userId = 1;
string userName = 2;
int32 age = 3;
string email = 4;
}
// 流式请求示例
message BatchUserReq {
string keyword = 1;
}
message BatchUserResp {
string name = 1;
int64 id = 2;
}
// RPC服务定义
service UserRpcService {
// 普通同步调用(对标REST GET/POST)
rpc getUserInfo(UserQueryReq) returns (UserQueryResp);
// 服务端流式返回(大数据分页、实时推送)
rpc listUserStream(BatchUserReq) returns (stream BatchUserResp);
}
执行maven compile,插件自动生成:Req/Resp实体、Grpc服务抽象Stub、服务基类,无需手动编写DTO。
五、第三步:gRPC服务端实现
1. application.yml 极简配置
spring:
application:
name: grpc-server-user
# gRPC内置配置,默认端口9090,无需额外Web容器
grpc:
server:
port: 9090
# 开启全局拦截器
interceptors:
- com.grpc.server.interceptor.GlobalGrpcInterceptor
2. 实现自动生成的RPC服务基类
import com.grpc.user.api.UserQueryReq;
import com.grpc.user.api.UserQueryResp;
import com.grpc.user.api.UserRpcServiceGrpc;
import io.grpc.stub.StreamObserver;
import net.devh.boot.grpc.server.service.GrpcService;
@GrpcService
publicclassUserRpcServiceImplextendsUserRpcServiceGrpc.UserRpcServiceImplBase {
/**
* 普通同步RPC接口,等价REST接口
*/
@Override
publicvoidgetUserInfo(UserQueryReq request, StreamObserver<UserQueryResp> responseObserver) {
// 1. 获取入参
LonguserId= request.getUserId();
// 2. 业务查询数据库
UserQueryRespresp= UserQueryResp.newBuilder()
.setUserId(userId)
.setUserName("测试用户")
.setAge(22)
.setEmail("test@xxx.com")
.build();
// 3. 返回结果
responseObserver.onNext(resp);
// 4. 结束本次调用
responseObserver.onCompleted();
}
/**
* 服务端流式返回,批量大数据分批推送
*/
@Override
publicvoidlistUserStream(BatchUserReq request, StreamObserver<BatchUserResp> responseObserver) {
Stringkeyword= request.getKeyword();
// 模拟分批流式推送多条数据
for (inti=1; i <= 10; i++) {
BatchUserRespdata= BatchUserResp.newBuilder()
.setId(i)
.setName(keyword + "_用户" + i)
.build();
responseObserver.onNext(data);
}
responseObserver.onCompleted();
}
}
3. 全局统一拦截器(日志、鉴权、耗时统计)
import io.grpc.*;
import net.devh.boot.grpc.server.interceptor.GrpcGlobalServerInterceptor;
@GrpcGlobalServerInterceptor
publicclassGlobalGrpcInterceptorimplementsServerInterceptor {
@Override
public <ReqT, RespT> ServerCall.Listener<ReqT> interceptCall(ServerCall<ReqT, RespT> call, Metadata headers, ServerCallHandler<ReqT, RespT> next) {
longstart= System.currentTimeMillis();
// 前置:鉴权、打印请求元数据、日志
ServerCall<ReqT, RespT> wrapCall = newForwardingServerCall.SimpleForwardingServerCall<>(call) {
@Override
publicvoidclose(Status status, Metadata trailers) {
// 后置:打印耗时、异常日志
longcost= System.currentTimeMillis() - start;
System.out.println("gRPC接口耗时:" + cost + "ms,状态:" + status.getCode());
super.close(status, trailers);
}
};
return next.startCall(wrapCall, headers);
}
}
4. SpringBoot4启动类(无额外注解)
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);
}
}
启动后自动占用9090端口提供gRPC服务,不依赖Tomcat,轻量无冗余。
六、第四步:gRPC客户端调用(SpringBoot4一键注入Stub)
1. 客户端application.yml配置
spring:
application:
name:grpc-client-demo
grpc:
client:
# 和服务端service名称对应
user-rpc-service:
address:static://127.0.0.1:9090
# 负载均衡策略 round_robin轮询
load-balancing-policy:round_robin
# 超时控制
default-deadline: 5000ms
2. 直接注入自动生成的Stub,像调用本地方法一样RPC
import com.grpc.user.api.UserQueryReq;
import com.grpc.user.api.UserQueryResp;
import com.grpc.user.api.UserRpcServiceGrpc;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
@RestController
publicclassGrpcTestController {
// 自动注入远程RPC代理,无需手动创建Channel、ManagedChannel
@Resource
private UserRpcServiceGrpc.UserRpcServiceBlockingStub userRpcStub;
@GetMapping("/rpc/user")
public UserQueryResp getUser(@RequestParam Long userId) {
// 构造请求
UserQueryReqreq= UserQueryReq.newBuilder()
.setUserId(userId)
.setUserName("客户端查询")
.build();
// 同步远程调用,和本地方法无差异
return userRpcStub.getUserInfo(req);
}
}
3. 流式调用示例
public voidstreamQuery() {
BatchUserReqreq= BatchUserReq.newBuilder().setKeyword("客户").build();
StreamObserver<BatchUserResp> respStream = newStreamObserver<>() {
@Override
publicvoidonNext(BatchUserResp value) {
// 接收流式分批数据
System.out.println("流式数据:" + value.getName());
}
@Override
publicvoidonError(Throwable t) {}
@Override
publicvoidonCompleted() {
System.out.println("流式数据接收完成");
}
};
userRpcStub.listUserStream(req, respStream);
}
七、全文总结
Spring Boot 4.0 搭配官方适配的gRPC Starter,仅4步即可完成完整微服务RPC通信:引入依赖→编写proto契约→实现服务端→客户端注入Stub调用。
对比传统REST接口,gRPC在序列化性能、传输体积、流式通信、内置治理能力上全面领先,微服务内网内部通信优先推荐使用。整套集成无复杂原生Netty、Channel管理代码,starter自动完成容器装配、生命周期管理,上手难度远低于原生gRPC,开发体验比REST更简洁高效。
微服务RPC通信是后端高频技术栈,gRPC、Dubbo、REST三种方案选型、性能调优、集群治理是面试与生产核心难点。后续持续更新gRPC进阶实战:双向流IM、服务注册发现、限流熔断、Proto最佳实践、与Dubbo性能压测对比。
喜欢微服务、高性能RPC架构干货,欢迎点赞、收藏、关注,持续跟进SpringBoot进阶专栏!
微信赞赏
支付宝扫码领红包
