SpringCloudAlibaba極簡(jiǎn)入門整合Grpc代替OpenFeign的詳細(xì)過(guò)程
前言
他來(lái)了他來(lái)了,停了快2個(gè)月了終于又開始更新文章啦,這次帶來(lái)的絕對(duì)是干貨?。?!。由于公司項(xiàng)目進(jìn)行重構(gòu)的時(shí)候考慮到,OpenFeign做為服務(wù)通信組件在高并發(fā)情況下有一定的性能瓶頸,所以將其替換為更高性能的通信組件Grpc,Grpc也是業(yè)界比較流行的服務(wù)通信組件,底層采用HTTP/2進(jìn)行網(wǎng)絡(luò)通信性能上高于基于Http/1.1的OpenFeign。 我將把Grpc的整合過(guò)程整理成文字分享給大家,喜歡請(qǐng)三連?。。?,你的鼓勵(lì)是我堅(jiān)持下去的動(dòng)力。
認(rèn)識(shí)Grpc
OpenFeign基于 HTTP/1.1 協(xié)議。主要使用 JSON 或 XML 格式進(jìn)行數(shù)據(jù)交換,這些格式更加人性化但分裝臃腫效率較低。其主要用于 RESTful API 調(diào)用,支持聲明式的 Web 服務(wù)客戶端。
而 gRPC 是一個(gè)高性能、開源和通用的 RPC(遠(yuǎn)程過(guò)程調(diào)用)框架,基于 Protocol Buffers 序列化協(xié)議開發(fā),在內(nèi)部實(shí)現(xiàn)上,它采用了 HTTP/2 協(xié)議作為傳輸層協(xié)議的一部分來(lái)實(shí)現(xiàn)高效的雙向流通信的能力等特性讓它成為很多開發(fā)者熱衷的工具庫(kù)之一;gRPC 在處理大量數(shù)據(jù)時(shí)表現(xiàn)優(yōu)異,適用于需要快速響應(yīng)的應(yīng)用場(chǎng)景,特別是在微服務(wù)架構(gòu)中。
gRPC:
- 強(qiáng)調(diào)高效的數(shù)據(jù)傳輸和低延遲通信。如金融交易、在線游戲等對(duì)延遲要求極高的場(chǎng)景
- 適合構(gòu)建高性能的分布式系統(tǒng)和服務(wù)間通信。在大規(guī)模微服務(wù)架構(gòu)中,gRPC 可以顯著提高系統(tǒng)的整體性能。
- 支持流式傳輸,可以實(shí)現(xiàn)長(zhǎng)連接和實(shí)時(shí)數(shù)據(jù)推送。
OpenFeign:
- 注重簡(jiǎn)化開發(fā)者的代碼編寫工作。
- 更加靈活,可以輕松地集成到現(xiàn)有的 Spring Boot 項(xiàng)目中。
- 適用于輕量級(jí)的 RESTful API 調(diào)用。
總結(jié)來(lái)說(shuō),gRPC 和 OpenFeign 各有優(yōu)勢(shì),選擇哪種技術(shù)取決于具體的業(yè)務(wù)需求和技術(shù)棧。如果你需要高性能、低延遲的服務(wù)間通信,gRPC 是更好的選擇;如果你希望簡(jiǎn)化開發(fā)流程并快速集成 RESTful API,OpenFeign 則更為合適。
案例實(shí)戰(zhàn)
1.搭建工程
首先搭建一個(gè)SpringBoot父工程,父工程下分別有:grpc-api ,grpc-provider ,grpc-consumer 三個(gè)模塊,分別代表:Grpc接口,生產(chǎn)者,消費(fèi)者。父工程管理的依賴如下
<properties> <maven.compiler.source>21</maven.compiler.source> <maven.compiler.target>21</maven.compiler.target> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <java.version>21</java.version> <skipTests>true</skipTests> <spring-cloud.version>2023.0.1</spring-cloud.version> <spring-cloud-alibaba.version>2023.0.1.0</spring-cloud-alibaba.version> <hutool.version>5.8.28</hutool.version> <lombok.version>1.18.32</lombok.version> </properties> <!--SpringBoot依賴--> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>3.3.0</version> </parent> <dependencies> <!-- 常用工具類 --> <dependency> <groupId>cn.hutool</groupId> <artifactId>hutool-all</artifactId> <version>${hutool.version}</version> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>${lombok.version}</version> <scope>provided</scope> </dependency> <!--SpringCloud 2020.* 禁用了bootstrap 而注冊(cè)中心等配置文件需要 bootstrap.yml 為名的配置文件--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-bootstrap</artifactId> </dependency> <!--注解配置器--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-configuration-processor</artifactId> <optional>true</optional> </dependency> </dependencies> <dependencyManagement> <dependencies> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-alibaba-dependencies</artifactId> <version>${spring-cloud-alibaba.version}</version> <type>pom</type> <scope>import</scope> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>${spring-cloud.version}</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement>
2.API模塊
api模塊需要導(dǎo)入grpc相關(guān)依賴,以及編寫proto文件,我們根據(jù)proto文件自動(dòng)生成Grpc的API接口文件,需要導(dǎo)入的依賴如下
<dependencies> <!-- https://mvnrepository.com/artifact/net.devh/grpc-server-spring-boot-starter --> <dependency> <groupId>net.devh</groupId> <artifactId>grpc-server-spring-boot-starter</artifactId> <version>3.0.0.RELEASE</version> </dependency> <dependency> <groupId>net.devh</groupId> <artifactId>grpc-client-spring-boot-starter</artifactId> <version>3.0.0.RELEASE</version> </dependency> <dependency> <groupId>javax.annotation</groupId> <artifactId>javax.annotation-api</artifactId> <version>1.3.2</version> </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> <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> </plugins> </build>
grpc-server-spring-boot-starter 和 grpc-client-spring-boot-starter 是Grpc的服務(wù)端和客戶端的依賴,javax.annotation-api是對(duì)Grpc代碼生成注解的支持,不導(dǎo)入該包會(huì)報(bào)錯(cuò)。然后導(dǎo)入了os-maven-plugin插件,以及 protobuf-maven-plugin 插件用來(lái)根據(jù)proto文件生成API代碼的。
接著我們?cè)貯PI模塊中main目錄下創(chuàng)建一個(gè)proto目錄,并創(chuàng)建一個(gè)文件User.proto
,內(nèi)容如下
syntax = "proto3"; /** 生產(chǎn)的代碼合并到一個(gè)文件 **/ option java_multiple_files = false; /** 生產(chǎn)代碼輸出的包路徑 **/ option java_package = "cn.whale.api.User"; /** API接口 **/ service UserApi { /** Grpc API 接口 **/ rpc getById(GetUserReq) returns (GetUserRep) {} } /** 響應(yīng)對(duì)象 **/ message GetUserReq { /** Long 用戶ID **/ int64 id = 1; } /** 結(jié)果對(duì)象 **/ message GetUserRep { /** Long 用戶ID **/ int64 id = 1; /** String 用戶名字 **/ string name = 2; }
該文件是用來(lái)定義Grpc Api接口的,具體請(qǐng)看上面的注釋,需要注意的是定義Protobuf 的 message 對(duì)象的字段類型可不能使用Java的類型,int64 對(duì)應(yīng)Long
, string 對(duì)應(yīng) String
具體請(qǐng)看:https://protobuf.com.cn/programming-guides/proto3/#specifying-types
編寫好proto文件后,對(duì)api模塊進(jìn)行compile(IDEA 右側(cè) - api模塊 - lifecycle - compile) ,然后會(huì)自動(dòng)在API模塊中生成Grpc相關(guān)的 API接口。
3.提供者服務(wù)
提供者服務(wù)首先是需要向Nacos注冊(cè)(其他注冊(cè)中心也行)的,然后導(dǎo)入api模塊,編寫Grpc的提供者服務(wù),導(dǎo)入如下依賴
<dependencies> <!--grpc api 模塊 --> <dependency> <groupId>cn.whale</groupId> <artifactId>grpc-api</artifactId> <version>1.0-SNAPSHOT</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!--nacos服務(wù)發(fā)現(xiàn)--> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId> </dependency> <!--配置管理 --> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId> </dependency> <!--grpc服務(wù)端依賴,api模塊中引入了,這里其實(shí)可以不引--> <dependency> <groupId>net.devh</groupId> <artifactId>grpc-server-spring-boot-starter</artifactId> <version>3.0.0.RELEASE</version> </dependency> </dependencies>
接著對(duì)提供者服務(wù)進(jìn)行配置,啟動(dòng)類正常寫,沒有什么新東西,bootstrap.yml配置如下
server: port: 8081 #tomcat 端口 grpc: server: port: 7071 #Grpc端口 client: #Grpic客戶端配置 GLOBAL: negotiation-type: plaintext #協(xié)議類型,明文傳輸,也可以使用TLS進(jìn)行加密傳輸,服務(wù)內(nèi)部通信使用明文即可 enable-keep-alive: true keep-alive-without-calls: true spring: application: name: grpc-provider #服務(wù)名 cloud: nacos: discovery: #服務(wù)注冊(cè) server-addr: nacos地址:8848 config: #配置管理 server-addr: ${spring.cloud.nacos.discovery.server-addr} file-extension: yml
接下來(lái)編寫提供者服務(wù)的Grpc實(shí)現(xiàn),創(chuàng)建一個(gè)類UserApiImpl
繼承UserApiGrpc
,具體如下
package cn.whale.grpc; import cn.whale.api.User.User; import cn.whale.api.User.UserApiGrpc; import io.grpc.stub.StreamObserver; import net.devh.boot.grpc.server.service.GrpcService; /** * 標(biāo)記Grpc提供者服務(wù) */ @GrpcService public class UserApiImpl extends UserApiGrpc.UserApiImplBase { /** * 接口方法實(shí)現(xiàn) * @param request :請(qǐng)求對(duì)象 * @param responseObserver : 消息流對(duì)象,用來(lái)響應(yīng)結(jié)果 */ @Override public void getById(User.GetUserReq request, StreamObserver<User.GetUserRep> responseObserver) { long id = request.getId(); //TODO :去數(shù)據(jù)查詢數(shù)據(jù) //封裝結(jié)果數(shù)據(jù) User.GetUserRep userRep = User.GetUserRep.newBuilder().setId(id).setName("zs").build(); //響應(yīng)結(jié)果 responseObserver.onNext(userRep); responseObserver.onCompleted(); //異常情況 //responseObserver.onError(exception); } }
- @GrpcService :Grpc的服務(wù)端注解
- UserApiGrpc.UserApiImplBase :根據(jù)Proto自動(dòng)生成的API接口
- getById :我們定義的API接口方法,具體請(qǐng)看代碼注釋
到這里提供者就編寫完成了,啟動(dòng)提供者服務(wù),可以看到Grpc的端口
4.消費(fèi)者服務(wù)
消費(fèi)者服務(wù)也是要做服務(wù)注冊(cè),然后引入api模塊,以及Grpc客戶端依賴,具體如下
<dependencies> <dependency> <groupId>cn.whale</groupId> <artifactId>grpc-api</artifactId> <version>1.0-SNAPSHOT</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId> </dependency> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId> </dependency> <dependency> <groupId>net.devh</groupId> <artifactId>grpc-client-spring-boot-starter</artifactId> <version>3.0.0.RELEASE</version> </dependency> </dependencies>
編寫啟動(dòng)類和創(chuàng)建bootstrap.yml文件
server: port: 8082 grpc: server: port: 7072 client: GLOBAL: negotiation-type: plaintext enable-keep-alive: true keep-alive-without-calls: true spring: application: name: grpc-consumer cloud: nacos: discovery: server-addr: nacos地址:8848 config: server-addr: ${spring.cloud.nacos.discovery.server-addr} file-extension: yml
接著我們編寫一個(gè)Conroller來(lái)實(shí)現(xiàn)和提供者的Grpc通信,代碼如下
@RestController @Slf4j public class BusinessController { //指向提供者的服務(wù)名 @GrpcClient(value = "grpc-provider") private UserApiGrpc.UserApiBlockingStub userApiBlockingStub; @GetMapping("/user") public String getUserById(){ User.GetUserRep getUserRep = userApiBlockingStub.getById(User.GetUserReq.newBuilder().setId(1L).build()); log.info("查詢到用戶信息,id = {},name = {}",getUserRep.getId(),getUserRep.getName()); return getUserRep.toString(); } }
- @GrpcClient(value = “grpc-provider”) : 客戶端注解,value指向了注冊(cè)中心的提供者服務(wù)的名字,底層會(huì)自動(dòng)進(jìn)行負(fù)載均衡
- UserApiGrpc.UserApiBlockingStub : Grpc 同步接口,它也支持異步調(diào)用UserApiGrpc.UserApiFutureStub
到這里消費(fèi)者就編寫完成了,啟動(dòng)消費(fèi)者,通過(guò)瀏覽器訪問/user,就可以拿到提供者返回的數(shù)據(jù)了
5.注意事項(xiàng)
最后說(shuō)幾個(gè)注意事項(xiàng)
- Grpc生成的對(duì)象只提供了Builder的方式設(shè)置值,所以沒辦法通過(guò)BeanUtils等工具進(jìn)行對(duì)象之間的自動(dòng)轉(zhuǎn)換的,需要手動(dòng)給Proto對(duì)象設(shè)置值。見生產(chǎn)者 User.GetUserRep
- 如果給Proto對(duì)象設(shè)置了空值會(huì)報(bào)錯(cuò),所以在給對(duì)象設(shè)置值的時(shí)候建議先判斷空值,然后給一個(gè)默認(rèn)值,比如:String為null,就指定一個(gè)“”空字符串
- Grpc是無(wú)法返回一個(gè)null對(duì)象的,所以消費(fèi)者端到底有沒有拿到一個(gè)有效的結(jié)果不能直接用null來(lái)判斷,需要取出具體的值來(lái)判斷
就寫到這把,剩下的坑大家自己去踩,如果文章對(duì)你有幫助請(qǐng)給個(gè)好評(píng)!??!
到此這篇關(guān)于SpringCloudAlibaba極簡(jiǎn)入門整合Grpc代替OpenFeign的文章就介紹到這了,更多相關(guān)SpringCloudAlibaba整合Grpc內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
k8s部署的java服務(wù)添加idea調(diào)試參數(shù)的方法
文章介紹了如何在K8S容器中的Java服務(wù)上進(jìn)行遠(yuǎn)程調(diào)試,包括配置Deployment、Service以及本地IDEA的調(diào)試設(shè)置,感興趣的朋友跟隨小編一起看看吧2025-02-02arthas?jprofiler做復(fù)雜鏈路的調(diào)用分析
這篇文章主要為大家介紹了arthas?jprofiler做復(fù)雜鏈路的調(diào)用分析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-06-06SpringBoot單機(jī)限流的實(shí)現(xiàn)
在系統(tǒng)運(yùn)維中, 有時(shí)候?yàn)榱吮苊庥脩舻膼阂馑⒔涌? 會(huì)加入一定規(guī)則的限流,本文主要介紹了SpringBoot單機(jī)限流的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2023-08-08Java下變量大小寫駝峰、大小寫下劃線、大小寫連線轉(zhuǎn)換
有時(shí)候需要處理對(duì)象屬性的getter、setter方法,或者將屬性與數(shù)據(jù)表字段進(jìn)行相互轉(zhuǎn)換,感興趣的可以了解一下2021-06-06Java使用JDBC或MyBatis框架向Oracle中插入XMLType數(shù)據(jù)
XMLType是Oracle支持的一種基于XML格式存儲(chǔ)的數(shù)據(jù)類型,這里我們共同來(lái)探究Java使用JDBC或MyBatis框架向Oracle中插入XMLType數(shù)據(jù)的方法:2016-07-07Android內(nèi)存泄漏實(shí)戰(zhàn)解析
Java是垃圾回收語(yǔ)言的一種。這篇文章主要介紹了Android內(nèi)存泄漏 的相關(guān)資料,需要的朋友可以參考下2016-10-10