日常接口开发绝大多数团队还在用 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. 1. REST:文本JSON,键名重复占用大量带宽,序列化/反序列化CPU消耗高;
  2. 2. gRPC:Protobuf 二进制编码,无冗余字段,体积缩减30%~70%,编解码速度提升数倍。

2. 底层协议

  1. 1. REST:HTTP/1.1,单请求单连接,头部臃肿,不支持长连接多路复用;
  2. 2. gRPC:HTTP/2 多路复用,单连接并发多请求,支持双向流、服务端流、客户端流。

3. 代码生成

  1. 1. REST:手动写DTO、Controller、接口文档,重复代码多;
  2. 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进阶专栏!

扫码领红包

微信赞赏支付宝扫码领红包

发表回复

后才能评论