Spring Boot集成gRPC的基本使用
Spring Boot集成gRPC的基本使用
一、gRPC底层原理
1.1 底层通信协议栈
gRPC的通信协议栈采用分层设计,从底层到上层依次为:
TCP协议 → HTTP/2协议 → gRPC协议 → 业务层
核心结论:gRPC本质是基于HTTP/2的RPC框架,依托TCP实现可靠传输,HTTP/2提供高效通信能力,gRPC封装协议细节和序列化逻辑。
1.1.1 各层核心作用
TCP层:最底层,负责建立可靠的字节流连接,保障数据不丢失、不重复、按序传输,核心是三次握手建立连接、四次挥手断开连接。
HTTP/2层:基于TCP之上,提供长连接、多路复用、二进制分帧、全双工流等核心能力,是gRPC高性能的关键。
gRPC层:封装RPC通信逻辑,包括接口定义、序列化/反序列化(默认Protobuf)、请求/响应转发。
业务层:开发者编写的接口实现、业务逻辑。
1.2 核心通信特性
1.2.1 通信方式
gRPC采用长连接、多路复用、全双工流式传输,具体特点:
长连接:客户端与服务端建立一次TCP连接后,保持连接状态,后续所有请求复用该连接,避免频繁建连/断连的性能损耗(区别于HTTP/1.1的短连接)。
多路复用:一条TCP连接上可以同时传输多个请求/响应(通过HTTP/2的流机制实现),互不干扰,提升连接利用率。
全双工:客户端和服务端可以同时向对方发送数据,无需等待对方响应,适合实时通信场景。
二进制分帧:HTTP/2将数据拆分为二进制帧传输,比HTTP/1.1的文本传输更高效、体积更小。
1.2.2 传输介质
传输介质为标准TCP Socket(网络流):
局域网内:通过网卡直接传输,延迟极低。
跨机器/跨网络:通过IP+端口定位服务端,依托网络链路(交换机、路由器)传输。
本质与MySQL、Redis、Dubbo等中间件的通信介质一致,都是基于TCP Socket。
1.2.3 握手机制
gRPC通信前会执行两层握手,确保连接合法、协议兼容:
TCP三次握手(强制):所有TCP通信的基础,用于建立可靠连接,流程如下:
客户端 → 服务端:发送SYN(请求建立连接)
服务端 → 客户端:发送SYN+ACK(确认请求,同时发起连接)
客户端 → 服务端:发送ACK(确认连接建立)
HTTP/2握手(强制):TCP连接建立后,协商HTTP/2协议版本、建立流(stream)、初始化长连接通道,无需开发者干预。
TLS握手(可选):开发环境可关闭(usePlaintext()),不执行TLS握手;生产环境开启加密时,会额外执行TLS握手,保障数据传输安全。
1.2.4 序列化机制
gRPC默认使用「Protobuf(Protocol Buffers)」作为序列化工具,核心优势:
二进制序列化,体积小(比JSON小30%-50%),传输效率高。
跨语言兼容(支持Java、Go、Python等多种语言),适合多语言微服务通信。
通过.proto文件定义接口,自动生成代码,减少手动编码工作量。
1.3 与主流通信方式的性能对比
对比gRPC与HTTP接口、Dubbo的核心差异:
| 通信方式 | 底层协议 | 连接方式 | 序列化方式 | 性能(QPS) | 适用场景 |
|---|---|---|---|---|---|
| gRPC | HTTP/2 + TCP | 长连接、多路复用 | Protobuf(二进制) | 极高(约10000+) | 微服务内部通信、跨语言通信、高并发场景 |
| Spring MVC(HTTP接口) | HTTP/1.1 + TCP | 短连接/连接池 | JSON(文本) | 一般(约3000-5000) | 前后端通信、对外接口 |
| Dubbo | TCP(默认) | 长连接 | Hessian/Kryo(二进制) | 高(约8000+) | Java微服务内部通信 |
二、gRPC集成Spring Boot细节
2.1 集成前提
JDK版本:必须为JDK8以上。
依赖版本:gRPC相关依赖版本必须统一,避免版本冲突。
2.2 核心依赖集成(pom.xml配置)
项目的pom.xml,核心依赖如下:
<properties><java.version>8</java.version><grpc.version>2.13.0.RELEASE</grpc.version><protobuf.version>3.19.4</protobuf.version><grpc-java.version>1.42.2</grpc-java.version></properties><dependencies><!-- gRPC核心依赖 --><dependency><groupId>net.devh</groupId><artifactId>grpc-spring-boot-starter</artifactId><version>${grpc.version}</version></dependency><!-- Protobuf序列化依赖(版本必须与编译器一致) --><dependency><groupId>com.google.protobuf</groupId><artifactId>protobuf-java</artifactId><version>${protobuf.version}</version></dependency><dependency><groupId>com.google.protobuf</groupId><artifactId>protobuf-java-util</artifactId><version>${protobuf.version}</version></dependency></dependencies><build><extensions><!-- 用于识别操作系统,适配Mac/Win10/Linux --><extension><groupId>kr.motd.maven</groupId><artifactId>os-maven-plugin</artifactId><version>1.7.0</version></extension></extensions><plugins><!-- gRPC编译插件(自动生成Java代码) --><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:${os.detected.classifier}</protocArtifact><pluginId>grpc-java</pluginId><pluginArtifact>io.grpc:protoc-gen-grpc-java:${grpc-java.version}:exe:${os.detected.classifier}</pluginArtifact></configuration><executions><execution><goals><goal>compile</goal><goal>compile-custom</goal></goals></execution></executions></plugin></plugins></build>2.3 关键配置说明(避坑重点)
2.3.1 版本号规范
项目版本号:<version>1.0.0</version>(纯数字,禁止写V1.0.0,否则protobuf插件不执行)。
依赖版本:protobuf.version、grpc-java.version必须匹配,咱们选用的3.19.4+1.42.2,适配Mac M系列+Win10,无编译报错。
2.3.2 生成代码目录说明
不能修改、不能移动、不能删除,否则编译报错。
IDEA中需右键标记为「Generated Sources Root」,否则识别不到类。
生成路径由.proto文件中的option java_package指定,配置示例:com.xxx.grpc.api。
2.3.3 @GrpcService注解说明
加了@GrpcService注解的类,会自动被Spring注册为Bean,同时被gRPC服务器加载,暴露接口供客户端调用:
作用等同于@Service,可正常注入其他Spring Bean(如Service、Mapper)。
必须继承XxxGrpc.XxxxlBase(自动生成的类),重写接口方法。
2.3.4 .proto文件规范
package:gRPC协议的命名空间(如com.xxx.grpc),用于避免接口重名,客户端和服务端必须一致。
option java_package:生成Java类的包路径(如com.xxx.grpc.api),决定代码生成位置。
客户端和服务端的.proto文件必须完全一致(一字不差),否则无法通信。
2.4 集成demo
- HelloWorld.proto的文件demo如下
syntax = "proto3"; package com.xxx.grpc; // 包名 // 生成的Java代码包路径 option java_package = "com.xxxx.grpc.api"; option java_outer_classname = "HelloProto"; option java_multiple_files = true; // 服务定义 service HelloService { // 响应 rpc QueryData (HelloRequest) returns (HelooResponse); } // 请求参数 message HelloRequest { string requestId = 1; string queryContent = 2; } // 响应结果 message HelooResponse { int32 code = 1; string message = 2; string data = 3; // 1、2、3只是字段顺序不是字节也不是长度 }- 实现类demo如下
GrpcServicepublicclassHelloServiceImplextendsHelloServiceGrpc.HelloServiceImplBase{/** * 处理请求 */@OverridepublicvoidqueryData(HelloRequestrequest,StreamObserver<HelloResponse>responseObserver){// 接收参数System.out.println("收到请求:requestId="+request.getRequestId());System.out.println("查询内容:"+request.getQueryContent());// 业务处理StringresultData="处理完成,返回数据:"+System.currentTimeMillis();// 构建响应HelloResponseresponse=HelloResponse.newBuilder().setCode(200).setMessage("成功").setData(resultData).build();// 返回responseObserver.onNext(response);responseObserver.onCompleted();}}- 客户端demo如下
privatestaticfinalStringSERVER_HOST="127.0.0.1";privatestaticfinalintSERVER_PORT=9191;publicstaticvoidmain(String[]args){// 构建通信通道ManagedChannelchannel=ManagedChannelBuilder.forAddress(SERVER_HOST,SERVER_PORT).usePlaintext()// 明文传输(开发环境用).build();// 创建客户端StubDataServiceGrpc.DataServiceBlockingStubclient=DataServiceGrpc.newBlockingStub(channel);// 构建请求参数DataRequestrequest=DataRequest.newBuilder().setRequestId("REQ_"+System.currentTimeMillis()).setQueryContent("我是客户端,请求服务端").build();try{// 调用服务端DataResponseresponse=client.queryData(request);// 输出结果System.out.println("===== 调用成功 =====");System.out.println("状态码:"+response.getCode());System.out.println("消息:"+response.getMessage());System.out.println("返回数据:"+response.getData());}catch(Exceptione){System.err.println("调用失败:"+e.getMessage());}finally{// 关闭通道channel.shutdown();}}三、核心总结
3.1 理论总结
底层:gRPC → HTTP/2 → TCP,依托TCP可靠传输,HTTP/2提供高效通信能力。
通信:长连接、多路复用、全双工,Protobuf二进制序列化,性能优于HTTP/JSON。
握手:必须执行TCP三次握手+HTTP/2握手,TLS握手可选。
3.2 选型建议
适合服务间高并发通信、跨语言通信;若需对外提供接口,可搭配Spring MVC;若为纯Java微服务,也可对比Dubbo,但gRPC跨语言优势更明显。
