一文詳解gRPC快速整合SpringCloud
gRPC
gRPC是由 google開發(fā)的一個高性能、通用的開源RPC框架,主要面向移動應(yīng)用開發(fā)且基于HTTP/2協(xié)議標(biāo)準(zhǔn)而設(shè)計,同時支持大多數(shù)流行的編程語言。它是一種與語言、平臺無關(guān)、可擴(kuò)展的序列化結(jié)構(gòu)數(shù)據(jù)。它的定位類似于JSON、XML,但是比他們更小、更快、更簡單。
優(yōu)勢
gRPC基于HTTP/2協(xié)議傳輸,而HTTP/2相比HTTP1.x,還是有需要優(yōu)勢的:
- HTTP/2采用二進(jìn)制格式傳輸協(xié)議,而非HTTP1.x的文本格式。

- 多路復(fù)用
HTTP/2支持通過一個連接發(fā)送多個并發(fā)的請求。
- 服務(wù)器推送
服務(wù)端推送是一種在客戶端請求之前發(fā)送數(shù)據(jù)的機(jī)制。在HTTP/2中,服務(wù)器可以對客戶端的一個請求發(fā)送多個響應(yīng)。而不像HTTP/1.X一樣,只能通過客戶端發(fā)起request,服務(wù)端才產(chǎn)生對應(yīng)的response。
- 減少網(wǎng)絡(luò)流量的頭部壓縮
HTTP/2對消息頭進(jìn)行了壓縮傳輸,能夠節(jié)省消息頭占用的網(wǎng)絡(luò)流量。
工作方式

從上圖可以看出,簡單了解一下grpc的工作模式。用gRPC來進(jìn)行遠(yuǎn)程調(diào)用服務(wù),客戶端(client) 僅僅需要gRPC Stub ,通過Proto Request向gRPC Server發(fā)起服務(wù)調(diào)用,然后 gRPC Server通過Proto Response(s)將調(diào)用結(jié)果返回給調(diào)用的client。
使用場景
- 接口約束: 需要對接口有嚴(yán)格的管控,比如對外部提供接口時,并不希望客戶端隨意傳遞數(shù)據(jù),這是我們就可以使用gRPC來對接口約束。
- 性能要求:對傳輸性能有較高要求,如果我們傳輸?shù)南Ⅲw過大,或調(diào)度過于頻繁不希望影響系統(tǒng)性能時,可以考慮使用gRPC,它的消息體比JSON或者文本傳輸要小的多。
Protobuf語法
基本規(guī)范
- 文件以.proto做為文件后綴,除結(jié)構(gòu)定義外的語句以分號結(jié)尾
- 結(jié)構(gòu)定義可以包含:message、service、enum
- rpc方法定義結(jié)尾的分號可有可無
- Message命名采用駝峰命名方式,字段命名采用小寫字母加下劃線分隔方式
- Enums類型名采用駝峰命名方式,字段命名采用大寫字母加下劃線分隔方式
- Service與rpc方法名統(tǒng)一采用駝峰式命名
message SongServerRequest {
required string song_name = 1;
}
enum Foo {
FIRST_VALUE = 1;
SECOND_VALUE = 2;
}
限定修飾符
- Required: 表示是一個必須字段,必須相對于發(fā)送方,在發(fā)送消息之前必須設(shè)置該字段的值,對于接收方,必須能夠識別該字段的意思。發(fā)送之前沒有設(shè)置required字段或者無法識別required字段都會引發(fā)編解碼異常,導(dǎo)致消息被丟棄。
- Optional:表示是一個可選字段,可選對于發(fā)送方,在發(fā)送消息時,可以有選擇性的設(shè)置或者不設(shè)置該字段的值。對于接收方,如果能夠識別可選字段就進(jìn)行相應(yīng)的處理,如果無法識別,則忽略該字段,消息中的其它字段正常處理。
- Repeated:表示該字段可以包含0~N個元素。其特性和optional一樣,但是每一次可以包含多個值??梢钥醋魇窃趥鬟f一個數(shù)組的值。
數(shù)據(jù)類型
| .proto | C++ | Java | Python | Go | Ruby | C# |
|---|---|---|---|---|---|---|
| double | double | double | float | float64 | Float | double |
| float | float | float | float | float32 | Float | float |
| int32 | int32 | int | int | int32 | Fixnum or Bignum | int |
| int64 | int64 | long | ing/long[3] | int64 | Bignum | long |
| uint32 | uint32 | int[1] | int/long[3] | uint32 | Fixnum or Bignum | uint |
| uint64 | uint64 | long[1] | int/long[3] | uint64 | Bignum | ulong |
| sint32 | int32 | int | intj | int32 | Fixnum or Bignum | int |
| sint64 | int64 | long | int/long[3] | int64 | Bignum | long |
| fixed32 | uint32 | int[1] | int | uint32 | Fixnum or Bignum | uint |
| fixed64 | uint64 | long[1] | int/long[3] | uint64 | Bignum | ulong |
| sfixed32 | int32 | int | int | int32 | Fixnum or Bignum | int |
| sfixed64 | int64 | long | int/long[3] | int64 | Bignum | long |
| bool | bool | boolean | boolean | bool | TrueClass/FalseClass | bool |
| string | string | String | str/unicode[4] | string | String(UTF-8) | string |
| bytes | string | ByteString | str | []byte | String(ASCII-8BIT) | ByteString |
gRPC整合SpringCloud & Nacos
其實,第一次了解gRPC,也是在Nacos2.0升級的時候,Nacos2.0版本相比1.X新增了gRPC的通信方式。
| 端口 | 與主端口的偏移量 | 描述 |
|---|---|---|
| 9848 | 1000 | 客戶端gRPC請求服務(wù)端端口,用于客戶端向服務(wù)端發(fā)起連接和請求 |
| 9849 | 1001 | 服務(wù)端gRPC請求服務(wù)端端口,用于服務(wù)間同步等 |
核心依賴
<properties>
<java.version>8</java.version>
<nacos.version>2.2.5.RELEASE</nacos.version>
<mapstruct.version>1.3.1.Final</mapstruct.version>
<grpc.starter.version>2.10.1.RELEASE</grpc.starter.version>
<grpc.client.version>2.10.1.RELEASE</grpc.client.version>
<lombok.version>1.18.12</lombok.version>
<fastjson.version>1.2.76</fastjson.version>
<freemarker.verson>2.3.28</freemarker.verson>
<nacos.client>2.0.0</nacos.client>
</properties>
<dependency>
<groupId>net.devh</groupId>
<artifactId>grpc-client-spring-boot-starter</artifactId>
<version>${grpc.client.version}</version>
</dependency>
<dependency>
<groupId>net.devh</groupId>
<artifactId>grpc-server-spring-boot-starter</artifactId>
<version>${grpc.starter.version}</version>
</dependency>
項目結(jié)構(gòu)

API
- 編寫pom配置。
<dependencies>
<dependency>
<groupId>net.devh</groupId>
<artifactId>grpc-server-spring-boot-starter</artifactId>
</dependency>
</dependencies>
<build>
<extensions>
<extension>
<groupId>kr.motd.maven</groupId>
<artifactId>os-maven-plugin</artifactId>
<version>1.6.2</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.12.0:exe:${os.detected.classifier}</protocArtifact>
<pluginId>grpc-java</pluginId>
<pluginArtifact>io.grpc:protoc-gen-grpc-java:1.34.1:exe:${os.detected.classifier}</pluginArtifact>
<!--設(shè)置grpc生成代碼到指定路徑-->
<outputDirectory>${project.basedir}/src/main/java</outputDirectory>
<!--生成代碼前是否清空目錄-->
<clearOutputDirectory>false</clearOutputDirectory>
</configuration>
<executions>
<execution>
<goals>
<goal>compile</goal>
<goal>compile-custom</goal>
</goals>
</execution>
</executions>
</plugin>
<!-- 設(shè)置多個源文件夾 -->
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>build-helper-maven-plugin</artifactId>
<version>3.0.0</version>
<executions>
<!-- 添加主源碼目錄 -->
<execution>
<id>add-source</id>
<phase>generate-sources</phase>
<goals>
<goal>add-source</goal>
</goals>
<configuration>
<sources>
<source>${project.basedir}/src/main/gen</source>
<source>${project.basedir}/src/main/java</source>
</sources>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
- 新建 src\main\proto 目錄,編寫 user.ptoto。
syntax = "proto3";
option java_multiple_files = true;
option java_package = "com.yx.grpc.user";
service UserService {
rpc queryUser(UserRequest) returns (UserReply) {}
}
message UserRequest {
int64 id = 2;
}
message UserReply {
int32 code = 1;
string msg = 2;
bool success = 3;
message Data {
UserPb userPb = 1;
}
Data data = 4;
}
message UserPb {
int64 id = 1;
string name = 2;
string sex = 3;
}
- 執(zhí)行 mvn compile,生成代碼。

服務(wù)端
- 核心服務(wù)實現(xiàn)類。
@GrpcService
public class UserServiceImpl extends UserServiceGrpc.UserServiceImplBase{
@Override
public void queryUser(UserRequest request, StreamObserver<UserReply> responseObserver) {
UserReply.Builder userReply = UserReply.newBuilder();
TblUser tblUser = new TblUser(11L, "syx", "nan");
userReply.setCode(200).setMsg("SUCCESS").setSuccess(true);
userReply.setData(UserReply.Data.newBuilder()
.setUserPb(UserPb.newBuilder()
.setId(tblUser.getId())
.setName(tblUser.getName())
.setSex(tblUser.getSex())));
responseObserver.onNext(userReply.build());
responseObserver.onCompleted();
super.queryUser(request, responseObserver);
}
}
客戶端
- gRPC配置。
grpc:
client:
GLOBAL:
negotiation-type: plaintext
enable-keep-alive: true
keep-alive-without-calls: true
- 自定義請求轉(zhuǎn)換器。
@Configuration
public class MessageConverter {
@Bean
public HttpMessageConverters protobufHttpMessageConverter() {
ProtobufHttpMessageConverter protobufHttpMessageConverter = new ProtobufHttpMessageConverter();
protobufHttpMessageConverter.setSupportedMediaTypes(Lists.newArrayList(MediaType.APPLICATION_JSON, MediaType.parseMediaType(MediaType.TEXT_PLAIN_VALUE + ";charset=ISO-8859-1")));
return new HttpMessageConverters(protobufHttpMessageConverter);
}
}
- 請求測試類。
@RestController
@RequestMapping("/user")
@Slf4j
public class UserController {
@GrpcClient("yx-grpc-service")
UserServiceGrpc.UserServiceFutureStub futureStub;
@RequestMapping(value="/queryUser/{id}")
public UserReply queryUser(@PathVariable Integer id) {
UserReply userReply = null;
try {
userReply = futureStub.queryUser(UserRequest.newBuilder().setId(id).build()).get();
return userReply;
} catch (Exception e) {
}
return userReply;
}
}
測試
啟動服務(wù)端和客戶端,訪問 http://localhost:8002/user/queryUser/1 。


Gitee 地址:gitee.com/renxiaoshi/…
以上就是一文詳解gRPC快速整合SpringCloud的詳細(xì)內(nèi)容,更多關(guān)于gRPC整合SpringCloud的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Springboot Autowried及Resouce使用對比解析
這篇文章主要介紹了Springboot Autowried及Resouce使用對比解析,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下2020-06-06
SpringMVC中常用參數(shù)校驗類注解使用示例教程
這篇文章主要介紹了SpringMVC中常用參數(shù)校驗類注解使用示例教程,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-03-03
SpringBoot實現(xiàn)全局異常處理方法總結(jié)
在項目開發(fā)中出現(xiàn)異常時很平常不過的事情,我們處理異常也有很多種方式。本文將詳細(xì)為大家講解SpringBoot實現(xiàn)全局異常處理幾種方法,感興趣的可以學(xué)習(xí)一下2022-03-03
SpringMVC加載控制與Postmand的使用和Rest風(fēng)格的引入及RestFul開發(fā)全面詳解
SpringMVC是一種基于Java,實現(xiàn)了Web MVC設(shè)計模式,請求驅(qū)動類型的輕量級Web框架,即使用了MVC架構(gòu)模式的思想,將Web層進(jìn)行職責(zé)解耦。基于請求驅(qū)動指的就是使用請求-響應(yīng)模型,框架的目的就是幫助我們簡化開發(fā),SpringMVC也是要簡化我們?nèi)粘eb開發(fā)2022-10-10

