日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 人文社科 > 生活经验 >内容正文

生活经验

SpringBoot整合Grpc实现跨语言RPC通讯

發布時間:2023/11/27 生活经验 39 豆豆
生活随笔 收集整理的這篇文章主要介紹了 SpringBoot整合Grpc实现跨语言RPC通讯 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

什么是gRPC

gRPC谷歌開源基于go語言的一個現代的開源高性能RPC框架,可以在任何環境中運行。它可以有效地連接數據中心內和跨數據中心的服務,并提供可插拔的支持,以實現負載平衡,跟蹤,健康檢查和身份驗證。它還適用于分布式計算的最后一英里,用于將設備,移動應用程序和瀏覽器連接到后端服務。

簡單的服務定義:使用Protocol Buffers定義您的服務,這是一個功能強大的二進制序列化工具集和語言.

跨語言和平臺工作:自動為各種語言和平臺的服務生成慣用的客戶端和服務器存根,當然單純的java語言之間也是可以的。

一般主要是Java和Go,PHP,Python之間通訊。

快速啟動并擴展:使用單行安裝運行時和開發環境,并使用框架每秒擴展到數百萬個RPC

雙向流媒體和集成的身份驗證:基于http/2的傳輸的雙向流和完全集成的可插拔身份驗證

官網地址:https://www.grpc.io/

這是一個可以運行的例子,本文基于此增加了一些代碼:https://codenotfound.com/grpc-java-example.html

這個例子使用的jar是grpc-spring-boot-starter@io.github.lognet

?

這個例子也可以參考:https://github.com/yidongnan/grpc-spring-boot-starter

不過這個例子使用的是另一個jar是grpc-spring-boot-starter@net.devh

?

說明:Thrift也可以實現跨語言的通訊,有人對此做了對比參考:開源RPC(gRPC/Thrift)框架性能評測

?

服務定義

與許多RPC系統一樣,gRPC基于定義服務的思想,指定可以使用其參數和返回類型遠程調用的方法。默認情況下,gRPC使用Protocol Buffers作為接口定義語言(IDL)來描述服務接口和有效負載消息的結構。如果需要,可以使用其他替代方案。

Protocol Buffers?是一種輕便高效的結構化數據存儲格式,可以用于結構化數據串行化,或者說序列化。

它很適合做數據存儲或?RPC?數據交換格式。可用于通訊協議、數據存儲等領域的語言無關、平臺無關、可擴展的序列化結構數據格式。

數據序列化和反序列化

序列化: 將數據結構或對象轉換成二進制串的過程。

反序列化:將在序列化過程中所生成的二進制串轉換成數據結構或者對象的過程。

這里有人翻譯了官方文檔:Protocol Buffers官方文檔(開發指南)

也可以看IBM的文檔:Google Protocol Buffer 的使用和原理

https://github.com/protocolbuffers/protobuf

https://developers.google.com/protocol-buffers/docs/javatutorial

參考官網指南:

如您所見,語法類似于C ++或Java。讓我們瀏覽文件的每個部分,看看它的作用。

.proto文件以包聲明開頭,這有助于防止不同項目之間的命名沖突。在Java中,包名稱用作Java包,除非您已經明確指定了a?java_package,就像我們在這里一樣。即使您提供了a?java_package,您仍應定義一個法線package,以避免在Protocol Buffers名稱空間和非Java語言中發生名稱沖突。

在包聲明之后,您可以看到兩個特定于Java的選項:?java_packagejava_outer_classname。?java_package指定生成的類應該以什么Java包名稱存在。如果沒有明確指定它,它只是匹配package聲明給出的包名,但這些名稱通常不是合適的Java包名(因為它們通常不以域名開頭)。該java_outer_classname選項定義應包含此文件中所有類的類名。如果你沒有java_outer_classname明確地給出,它將通過將文件名轉換為camel case來生成。例如,默認情況下,“my_proto.proto”將使用“MyProto”作為外部類名。

接下來,您有消息定義。消息只是包含一組類型字段的聚合。許多標準的簡單數據類型都可以作為字段類型,

包括boolint32floatdouble,和string。您還可以使用其他消息類型作為字段類型在消息中添加更多結構 - 在上面的示例中,Person消息包含PhoneNumber消息,而AddressBook消息包含Person消息。您甚至可以定義嵌套在其他消息中的消息類型 -?? 如您所見,PhoneNumber類型在內部定義Personenum如果您希望其中一個字段具有預定義的值列表之一,您也可以定義類型 - 在此您要指定電話號碼可以是其中之一MOBILEHOME或者WORK

每個元素上的“= 1”,“= 2”標記標識該字段在二進制編碼中使用的唯一“標記”。標簽號1-15需要少于一個字節來編碼而不是更高的數字,因此作為優化,您可以決定將這些標簽用于常用或重復的元素,將標簽16和更高版本留給不太常用的可選元素。重復字段中的每個元素都需要重新編碼標記號,因此重復字段特別適合此優化。

必須使用以下修飾符之一注釋每個字段:

  • required:必須提供該字段的值,否則該消息將被視為“未初始化”。嘗試構建一個未初始化的消息將拋出一個RuntimeException。解析未初始化的消息將拋出一個IOException。除此之外,必填字段的行為與可選字段完全相同。
  • optional:該字段可能已設置,也可能未設置。如果未設置可選字段值,則使用默認值。對于簡單類型,您可以指定自己的默認值,就像我們type在示例中為電話號碼所做的那樣。否則,使用系統默認值:數字類型為0,字符串為空字符串,bools為false。對于嵌入式消息,默認值始終是消息的“默認實例”或“原型”,其中沒有設置其字段。調用訪問器以獲取尚未顯式設置的可選(或必需)字段的值始終返回該字段的默認值。
  • repeated:該字段可以重復任意次數(包括零)。重復值的順序將保留在協議緩沖區中。將重復字段視為動態大小的數組。

永遠是必需的?你應該非常小心地將字段標記為required。如果您希望在某個時刻停止寫入或發送必填字段,則將字段更改為可選字段會有問題 - 舊讀者會認為沒有此字段的郵件不完整,可能會無意中拒絕或丟棄它們。您應該考慮為緩沖區編寫特定于應用程序的自定義驗證例程。谷歌的一些工程師得出的結論是,使用required弊大于利;?他們更喜歡只使用optionalrepeated。但是,這種觀點并不普遍。

.proto可以在Protocol Buffer Language Guide中找到編寫文件的完整指南- 包括所有可能的字段類型。不要去尋找類繼承類似的工具,但協議緩沖區不會這樣做。

?

如果你還不是很理解,就只要參考下面這個例子就行了。

我們將使用以下工具/框架:

  • gRPC 1.16
  • Spring Boot 2.1
  • Maven 3.5

我們的項目具有以下目錄結構:

?

使用Protocol Buffers定義服務

先看proto文件

syntax = "proto3";option java_multiple_files = true;
package com.codenotfound.grpc.helloworld;message Person {string first_name = 1;string last_name = 2;
}message Greeting {string message = 1;
}message A1 {int32  a = 1;int32  b = 2;
}message A2 {int32  message = 1;
}service HelloWorldService {rpc sayHello (Person) returns (Greeting);rpc addOperation (A1) returns (A2);
}

注意:A1,A2是我定義的,其實就是定義入參出參,1和2那是表示是第幾個參數而已,數據類型有string和int32。

?

Maven設置

我們使用Maven構建并運行我們的示例。

下面顯示的是POM文件中Maven項目的XML表示。它包含編譯和運行示例所需的依賴項。

為了配置和公開Hello World gRPC服務端點,我們將使用Spring Boot項目。

為了便于管理不同的Spring依賴項,使用了Spring Boot Starters。這些是一組方便的依賴項描述符,您可以在應用程序中包含這些描述符。

我們包含spring-boot-starter-web依賴項,該依賴項自動設置將托管我們的gRPC服務端點的嵌入式Apache Tomcat。

spring-boot-starter-test包括用于包括測試啟動的應用程序的依賴關系的JUnit,Hamcrest和的Mockito。

用于gRPC框架的Spring啟動啟動程序自動配置并運行嵌入式gRPC服務器,@GRpcService啟用Beans作為Spring Boot應用程序的一部分。啟動器支持Spring Boot版本1.5.X和2.XX我們通過包含grpc-spring-boot-starter依賴項來啟用它。

協議緩沖區支持許多編程語言中生成的代碼。本教程重點介紹Java。

有多種方法可以生成基于protobuf的代碼,在本例中,我們將使用grobc-java?GitHub頁面上記錄的protobuf-maven-plugin。

我們還包括os-maven-plugin擴展,它可以生成各種有用的平臺相關項目屬性。由于協議緩沖區編譯器是本機代碼,因此需要此信息。換句話說,protobuf-maven-plugin需要為正在運行的平臺獲取正確的編譯器。

最后,插件部分包括spring-boot-maven-plugin。這允許我們構建一個可運行的超級jar。這是執行和傳輸代碼的便捷方式。此外,該插件允許我們通過Maven命令啟動示例。

項目的pom文件:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><groupId>com.codenotfound</groupId><artifactId>grpc-java-hello-world</artifactId><version>0.0.1-SNAPSHOT</version><packaging>jar</packaging><name>grpc-java-hello-world</name><description>gRPC Java Example</description><url>https://codenotfound.com/grpc-java-example.html</url><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.1.0.RELEASE</version><relativePath /> <!-- lookup parent from repository --></parent><properties><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding><project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding><java.version>1.8</java.version><grpc-spring-boot-starter.version>3.0.0</grpc-spring-boot-starter.version><os-maven-plugin.version>1.6.1</os-maven-plugin.version><protobuf-maven-plugin.version>0.6.1</protobuf-maven-plugin.version></properties><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>io.github.lognet</groupId><artifactId>grpc-spring-boot-starter</artifactId><version>${grpc-spring-boot-starter.version}</version></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency></dependencies><build><extensions><extension><groupId>kr.motd.maven</groupId><artifactId>os-maven-plugin</artifactId><version>${os-maven-plugin.version}</version></extension></extensions><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId></plugin><plugin><groupId>org.xolstice.maven.plugins</groupId><artifactId>protobuf-maven-plugin</artifactId><version>${protobuf-maven-plugin.version}</version><configuration><protocArtifact>com.google.protobuf:protoc:3.5.1-1:exe:${os.detected.classifier}</protocArtifact><pluginId>grpc-java</pluginId><pluginArtifact>io.grpc:protoc-gen-grpc-java:1.16.1:exe:${os.detected.classifier}</pluginArtifact></configuration><executions><execution><goals><goal>compile</goal><goal>compile-custom</goal></goals></execution></executions></plugin></plugins></build></project>

注意:必須使用這個編譯compile工具生成特定語言(比如我們這里是java)的執行代碼。

手動執行以下Maven命令,應在target / generated-sources / protobuf /下生成不同的消息和服務類。

mvn compile

也可以使用IDE編譯。

編譯執行:

會生成編譯后的文件:

注意上面的文件是自動編譯生成的,不是你自己寫的!

?

Spring Boot安裝程序

創建一個SpringGrpcApplication包含一個main()方法,該方法使用Spring Boot的SpringApplication.run()方法來引導應用程序。

package com.codenotfound;import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;@SpringBootApplication
public class SpringGrpcApplication {public static void main(String[] args) {SpringApplication.run(SpringGrpcApplication.class, args);}
}

?

創建服務器

定義Service,我增加了一個加法運算方法,需要注意的是輸入,輸出參數都寫在方法定義里。

服務實現在HelloWorldServiceImplPOJO中定義,該POJO實現HelloWorldServiceImplBase從HelloWorld.proto文件生成的類。

我們覆蓋該sayHello()方法并Greeting根據Person請求中傳遞的名字和姓氏生成響應。

請注意,響應是一個StreamObserver對象。換句話說,該服務默認是異步的。在接收響應時是否要阻止是客戶的決定,我們將在下面進一步了解。

我們使用響應觀察者的onNext()方法返回Greeting,然后調用響應觀察者的onCompleted()方法告訴gRPC我們已經完成了寫響應。

HelloWorldServiceImplPOJO標注有@GRpcService其自動配置到端口露出指定GRPC服務默認端口6565。

request:入參

responseObserver:出參

格式按照標準

package com.codenotfound.grpc;import com.codenotfound.grpc.helloworld.A1;
import com.codenotfound.grpc.helloworld.A2;
import org.lognet.springboot.grpc.GRpcService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.codenotfound.grpc.helloworld.Greeting;
import com.codenotfound.grpc.helloworld.HelloWorldServiceGrpc;
import com.codenotfound.grpc.helloworld.Person;
import io.grpc.stub.StreamObserver;@GRpcService
public class HelloWorldServiceImplextends HelloWorldServiceGrpc.HelloWorldServiceImplBase {private static final Logger LOGGER= LoggerFactory.getLogger(HelloWorldServiceImpl.class);@Overridepublic void sayHello(Person request,StreamObserver<Greeting> responseObserver) {LOGGER.info("server received {}", request);String message = "Hello " + request.getFirstName() + " "+ request.getLastName() + "!";Greeting greeting= Greeting.newBuilder().setMessage(message).build();LOGGER.info("server responded {}", greeting);System.out.println("message>>>" + message);responseObserver.onNext(greeting);responseObserver.onCompleted();}@Overridepublic void addOperation(A1 request,StreamObserver<A2> responseObserver) {LOGGER.info("server received {}", request);int message = request.getA() + request.getB();A2 a2 = A2.newBuilder().setMessage(message).build();LOGGER.info("server responded {}", a2);System.out.println("message>>>" + message);responseObserver.onNext(a2);responseObserver.onCompleted();}
}

服務端使用了@GRpcService注解.

?

也可以使用這個jar注解@GrpcService就可以,代碼和前面一種一致的

<dependency><groupId>net.devh</groupId><artifactId>grpc-spring-boot-starter</artifactId><version>2.5.1.RELEASE</version>
</dependency>

https://github.com/yidongnan/grpc-spring-boot-starter/blob/master/README-zh.md

?

源碼在這里:

?你可以自定義端口:

grpc:port: 9090

?

創建客戶端

下面是客戶端代碼,這里為了簡單服務端和客戶端寫一個項目,實際開發肯定是分開,不然也就沒必要用Grpc這么麻煩了。?

客戶端代碼在HelloWorldClient類中指定。

@Component如果啟用了自動組件掃描,我們將使用Spring?注釋客戶端,這將導致Spring自動創建并將下面的bean導入容器(將@SpringBootApplication注釋添加到主SpringWsApplication類等同于使用@ComponentScan)。

要調用gRPC服務方法,我們首先需要創建一個stub

有兩種類型的stub可用:

  • 一個阻塞/同步stub,將等待服務器響應
  • 一個非阻塞/異步stub使非阻塞調用到服務器,其中,所述響應是異步返回。

在此示例中,我們將實現阻塞stub

為了傳輸消息,gRPC使用http/2和其間的一些抽象層。這種復雜性隱藏在MessageChannel處理連接的背后。

一般建議是為每個應用程序使用一個通道并在服務stub之間共享它。

我們使用一個init()帶注釋的方法@PostConstruct,以便MessageChannel在bean初始化之后構建一個新的權限。然后使用該通道創建helloWorldServiceBlockingStub

gRPC默認使用安全連接機制,如TLS。因為這是一個簡單的開發測試將使用usePlaintext(),以避免必須配置不同的安全工件,如密鑰/信任存儲。

sayHello()方法使用Builder模式創建Person對象,我們在其上設置'firstname'和'lastname'輸入參數。

helloWorldServiceBlockingStub則用來發送走向世界您好GRPC服務的請求。結果是一個Greeting對象,我們從中返回包含消息。

package com.codenotfound.grpc;import com.codenotfound.grpc.helloworld.A1;
import com.codenotfound.grpc.helloworld.A2;
import javax.annotation.PostConstruct;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import com.codenotfound.grpc.helloworld.Greeting;
import com.codenotfound.grpc.helloworld.HelloWorldServiceGrpc;
import com.codenotfound.grpc.helloworld.Person;
import io.grpc.ManagedChannel;
import io.grpc.ManagedChannelBuilder;@Component
public class HelloWorldClient {private static final Logger LOGGER= LoggerFactory.getLogger(HelloWorldClient.class);private HelloWorldServiceGrpc.HelloWorldServiceBlockingStub helloWorldServiceBlockingStub;@PostConstructprivate void init() {ManagedChannel managedChannel = ManagedChannelBuilder.forAddress("localhost", 9090).usePlaintext().build();helloWorldServiceBlockingStub = HelloWorldServiceGrpc.newBlockingStub(managedChannel);}public String sayHello(String firstName, String lastName) {Person person = Person.newBuilder().setFirstName(firstName).setLastName(lastName).build();LOGGER.info("client sending {}", person);Greeting greeting = helloWorldServiceBlockingStub.sayHello(person);LOGGER.info("client received {}", greeting);return greeting.getMessage();}public int addOperation(int a, int b) {A1 a1 = A1.newBuilder().setA(a).setB(b).build();A2 a2 = helloWorldServiceBlockingStub.addOperation(a1);return a2.getMessage();}
}

注意如果使用自定義端口需要修改這個,默認是6565,保持和你修改的配置文件一致,或者你不配置用默認的就行:

?

gRPC測試用例

package com.codenotfound;import static org.assertj.core.api.Assertions.assertThat;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import com.codenotfound.grpc.HelloWorldClient;@RunWith(SpringRunner.class)
@SpringBootTest
public class SpringGrpcApplicationTests {@Autowiredprivate HelloWorldClient helloWorldClient;@Testpublic void testSayHello() {assertThat(helloWorldClient.sayHello("Grpc", "Java")).isEqualTo("Hello Grpc Java!");assertThat(helloWorldClient.addOperation(1, 2)).isEqualTo(3);}
}

2個斷言:

一個是原始的就是字符串輸出,第二個是我增加的做個簡單的加法運算1+2=3就對了。

?

運行測試用例:

?

故意修改為和4比較結果,報錯就對了。

總結:建議先跑完整的例子,不要陷入grpc太深。

定義好.proto,再生成對應編譯文件,再寫實現類,定義服務端,使用客戶端調用。?

總結

以上是生活随笔為你收集整理的SpringBoot整合Grpc实现跨语言RPC通讯的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

主站蜘蛛池模板: 狠狠伊人| 欧美日韩国产精品成人 | 欧美色综合色 | 好色先生tv官网 | 久久黄色一级视频 | 天天操好逼 | 中文字幕一区二区三区人妻电影 | 97国产| 99久热在线精品996热是什么 | 中文字幕美女 | 成人精品视频在线播放 | 小草av在线 | jizzjizz欧美69巨大 | 久久泄欲网 | 呦呦视频在线观看 | 爱草在线视频 | 欧美日韩小视频 | 中文字幕在线欧美 | 中文字幕99页| 国产精品区一 | 福利国产在线 | 爱搞逼综合网 | 成人免费看片在线观看 | 中国一级片黄色一级片黄 | 午夜神马影院 | 天天av综合| 一区=区三区乱码 | 午夜精品一区二区三区在线播放 | 91视频插插插 | gay男互凵gay男同偷精 | 视频免费在线 | 在线观看av黄色 | 国产三级在线观看完整版 | 久久久久99精品成人片三人毛片 | 久久久av电影 | 欧美一区网站 | 免费看一区二区三区 | 一级a毛片 | 久久久久久亚洲av无码专区 | 99精品国产一区 | 男人肌肌桶女人肌肌 | 精品久久在线观看 | 天天干天天色天天 | 国产精品区一区二 | 夜夜导航 | 成人免费av片 | 日韩久久免费视频 | 婷婷九月综合 | 精品国产大片大片大片 | 亚洲综合专区 | 精品三级电影 | 97久久久久久久 | 国产aⅴ爽av久久久久成人 | 免费看av的网址 | 日本高清网站 | 亚洲国产精品无码专区 | 久久久久久久久久电影 | 夜夜夜综合 | 亚洲一区二区三区在线播放 | 中文字幕在线看片 | 在线观看深夜视频 | 午夜小福利 | 午夜亚洲精品 | 韩日一区 | 黄色私人影院 | 日韩丰满少妇 | 热@国产 | 一本色道久久88亚洲精品综合 | 无码少妇一区二区三区 | 一区二区三区 欧美 | 蜜桃精品视频 | 最近中文字幕av | 男女扒开双腿猛进入爽爽免费 | 久久精品99久久久久久久久 | 国产黄色片网站 | 性欧美巨大 | 午夜影院操 | 三级性生活片 | 97超碰免费在线 | 日本两性视频 | 久久黄色视| 国产精品午夜未成人免费观看 | 国产精品国产精品 | 亚洲日本japanese丝袜 | 每日更新av| 狠狠伊人 | 国产亚洲精品久 | 97色爱| 日韩久久久久久久久久久 | 手机看片国产日韩 | 公交上高潮的丁芷晴 | 欧美第一色 | 精品国产精品国产偷麻豆 | 国产成人啪免费观看软件 | 色婷婷天堂| 亚洲自拍在线观看 | 啦啦啦av| 国产精品天天狠天天看 | 香蕉一区二区三区四区 |