自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

一個(gè)簡(jiǎn)單的案例入門(mén) gRPC

開(kāi)發(fā) 項(xiàng)目管理
小伙伴們看到,這里首先需要和服務(wù)端建立連接,給出服務(wù)端的地址和端口號(hào)即可,usePlaintext() 方法表示不使用 TLS 對(duì)連接進(jìn)行加密(默認(rèn)情況下會(huì)使用 TLS 對(duì)連接進(jìn)行加密),生產(chǎn)環(huán)境建議使用加密連接。

這篇文章本來(lái)要在年前和小伙伴們見(jiàn)面,但是因?yàn)槲抑暗?Mac 系統(tǒng)版本是 10.13.6,這個(gè)版本比較老,時(shí)至今天在運(yùn)行一些新鮮玩意的時(shí)候有時(shí)候會(huì)有一些 BUG(例如運(yùn)行最新版的 Nacos 等),運(yùn)行 gRPC 的插件也有 BUG,代碼總是生成有問(wèn)題,但是因?yàn)橄到y(tǒng)升級(jí)是一個(gè)大事,所以一直等到過(guò)年放假,在家才慢慢折騰將 Mac 升級(jí)到目前的 13.1 版本,之前這些問(wèn)題現(xiàn)在都沒(méi)有了,gRPC 的案例現(xiàn)在也可以順利跑起來(lái)了。

所以今天就來(lái)和小伙伴們簡(jiǎn)單聊一聊 gRPC。

1. 緣起

我為什么想寫(xiě)一篇 gRPC 的文章呢?其實(shí)本來(lái)我是想和小伙伴們梳理一下在微服務(wù)中都有哪些跨進(jìn)城調(diào)用的方式,在梳理的過(guò)程中想到了 gRPC,發(fā)現(xiàn)還沒(méi)寫(xiě)文章和小伙伴們聊過(guò) gRPC,因此打算先來(lái)幾篇文章和小伙伴們?cè)敿?xì)介紹一下 gRPC,然后再梳理微服務(wù)中的跨進(jìn)程方案。

2. 什么是 gRPC

了解 gRPC 之前先來(lái)看看什么是 RPC。

RPC 全稱是 Remote Procedure Call,中文一般譯作遠(yuǎn)程過(guò)程調(diào)用。RPC 是一種進(jìn)程間的通信模式,程序分布在不同的地址空間里。簡(jiǎn)單來(lái)說(shuō),就是兩個(gè)進(jìn)程之間互相調(diào)用的一種方式。

gRPC 則是一個(gè)由 Google 發(fā)起的開(kāi)源的 RPC 框架,它是一個(gè)高性能遠(yuǎn)程過(guò)程調(diào)用 (RPC) 框架,可以在任何環(huán)境中運(yùn)行。gRPC 通過(guò)對(duì)負(fù)載均衡、跟蹤、健康檢查和身份驗(yàn)證的可插拔支持,有效地連接數(shù)據(jù)中心內(nèi)和數(shù)據(jù)中心之間的服務(wù)。

在 gRPC 中,客戶端應(yīng)用程序可以直接調(diào)用部署在不同機(jī)器上的服務(wù)端應(yīng)用程序中的方法,就好像它是本地對(duì)象一樣,使用 gRPC 可以更容易地創(chuàng)建分布式應(yīng)用程序和服務(wù)。與許多 RPC 系統(tǒng)一樣,gRPC 基于定義服務(wù)的思想,指定基于參數(shù)和返回類型遠(yuǎn)程調(diào)用的方法。在服務(wù)端側(cè),服務(wù)端實(shí)現(xiàn)接口,運(yùn)行 gRPC 服務(wù),處理客戶端調(diào)用。在客戶端側(cè),客戶端擁有存根(Stub,在某些語(yǔ)言中稱為客戶端),它提供與服務(wù)端相同的方法。

圖片

gRPC 客戶端和服務(wù)端可以在各種環(huán)境中運(yùn)行和相互通信 – 從 Google 內(nèi)部的服務(wù)器到你自己的桌面 – 并且可以使用 gRPC 支持的任何語(yǔ)言編寫(xiě)。因此,你可以輕松地用 Java 創(chuàng)建 gRPC 服務(wù)端,使用 Go、Python 或 Ruby 創(chuàng)建客戶端。此外,最新的 Google API 將包含 gRPC 版本的接口,使你輕松地將 Google 功能構(gòu)建到你的應(yīng)用程序中。

gRPC 支持的語(yǔ)言版本:

圖片

說(shuō)了這么多,還是得整兩個(gè)小案例小伙伴們可能才會(huì)清晰,所以我們也不廢話了,上案例。

3. 實(shí)踐

先來(lái)看下我們的項(xiàng)目結(jié)構(gòu):

├── grpc-api
│ ├── pom.xml
│ ├── src
├── grpc-client
│ ├── pom.xml
│ ├── src
├── grpc-server
│ ├── pom.xml
│ ├── src
└── pom.xml

大家看下,這里首先有一個(gè) grpc-api,這個(gè)模塊用來(lái)放我們的公共代碼;grpc-server 是我們的服務(wù)端,grpc-client 則是我們的客戶端,這些都是普通的 maven 項(xiàng)目。

3.1 grpc-api

在 grpc-api 中,我們首先引入項(xiàng)目依賴,如下:

<dependencies>
<dependency>
<groupId>io.grpc</groupId>
<artifactId>grpc-netty-shaded</artifactId>
<version>1.52.1</version>
</dependency>
<dependency>
<groupId>io.grpc</groupId>
<artifactId>grpc-protobuf</artifactId>
<version>1.52.1</version>
</dependency>
<dependency>
<groupId>io.grpc</groupId>
<artifactId>grpc-stub</artifactId>
<version>1.52.1</version>
</dependency>
<dependency> <!-- necessary for Java 9+ -->
<groupId>org.apache.tomcat</groupId>
<artifactId>annotations-api</artifactId>
<version>6.0.53</version>
<scope>provided</scope>
</dependency>
</dependencies>

除了這些常規(guī)的依賴之外,還需要一個(gè)插件:

<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.21.7:exe:${os.detected.classifier}</protocArtifact>
<pluginId>grpc-java</pluginId>
<pluginArtifact>io.grpc:protoc-gen-grpc-java:1.51.0:exe:${os.detected.classifier}</pluginArtifact>
</configuration>
<executions>
<execution>
<goals>
<goal>compile</goal>
<goal>compile-custom</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>

我來(lái)說(shuō)一下這個(gè)插件的作用。

默認(rèn)情況下,gRPC 使用 Protocol Buffers,這是 Google 提供的一個(gè)成熟的開(kāi)源的跨平臺(tái)的序列化數(shù)據(jù)結(jié)構(gòu)的協(xié)議,我們編寫(xiě)對(duì)應(yīng)的 proto 文件,通過(guò)上面這個(gè)插件可以將我們編寫(xiě)的 proto 文件自動(dòng)轉(zhuǎn)為對(duì)應(yīng)的 Java 類。

多說(shuō)一句,使用 Protocol Buffers 并不是必須的,也可以使用 JSON 等,但是目前來(lái)說(shuō)這個(gè)場(chǎng)景更常用的還是 Portal Buffers。

接下來(lái)我們?cè)?main 目錄下新建 proto 文件夾,如下:

圖片

注意,這個(gè)文件夾位置是默認(rèn)的。如果我們的 proto 文件不是放在 src/main/proto 位置,那么在配置插件的時(shí)候需要指定 proto 文件的位置,咱們本篇文章主要是入門(mén),我這里就使用默認(rèn)的位置。

在 proto 文件夾中,我們新建一個(gè) product.proto 文件,內(nèi)容如下:

syntax = "proto3";

option java_multiple_files = true;
option java_package = "org.javaboy.grpc.demo";
option java_outer_classname = "ProductProto";

package product;

service ProductInfo {
rpc addProduct (Product) returns (ProductId);
rpc getProduct(ProductId) returns(Product);
}

message Product {
string id = 1;
string name=2;
string descriptinotallow=3;
float price=4;
}

message ProductId {
string value = 1;
}

這段配置算是一個(gè)比較核心的配置了,這里主要說(shuō)明了負(fù)責(zé)進(jìn)程傳輸?shù)念悺⒎椒ǖ鹊降资莻€(gè)啥樣子:

  1. syntax = "proto3";:這個(gè)是 protocol buffers 的版本。
  2. option java_multiple_files = true;:這個(gè)字段是可選的,如果設(shè)置為 true,表示每一個(gè) message 文件都會(huì)有一個(gè)單獨(dú)的 class 文件;否則,message 全部定義在 outerclass 文件里。
  3. option java_package = "org.javaboy.grpc.demo";:這個(gè)字段是可選的,用于標(biāo)識(shí)生成的 java 文件的 package。如果沒(méi)有指定,則使用 proto 里定義的 package,如果package 也沒(méi)有指定,那就會(huì)生成在根目錄下。
  4. option java_outer_classname = "ProductProto";:這個(gè)字段是可選的,用于指定 proto 文件生成的 java 類的 outerclass 類名。什么是 outerclass?簡(jiǎn)單來(lái)說(shuō)就是用一個(gè) class 文件來(lái)定義所有的 message 對(duì)應(yīng)的 Java 類,這個(gè) class 就是 outerclass;如果沒(méi)有指定,默認(rèn)是 proto 文件的駝峰式;
  5. package product;:這個(gè)屬性用來(lái)定義 message 的包名。包名的含義與平臺(tái)語(yǔ)言無(wú)關(guān),這個(gè) package 僅僅被用在 proto 文件中用于區(qū)分同名的 message 類型。可以理解為 message 全名的前綴,和 message 名稱合起來(lái)唯一標(biāo)識(shí)一個(gè) message 類型。當(dāng)我們?cè)?proto 文件中導(dǎo)入其他 proto 文件的 message,需要加上 package 前綴才行。所以包名是用來(lái)唯一標(biāo)識(shí) message 的。
  6. service:我們定義的跨平臺(tái)方法都寫(xiě)在 service 中,上面的案例中我們定義了兩個(gè)方法:addProduct 表示添加一件商品,參數(shù)是一個(gè) Product 對(duì)象,返回值則是剛剛添加成功的商品的 ID;getProduct 則表示根據(jù) ID 查詢一個(gè)商品,參數(shù)是一個(gè)商品 ID,返回值則是查詢到的商品對(duì)象。這里的定義相當(dāng)于一個(gè)接口,將來(lái)我們要在 Java 代碼中實(shí)現(xiàn)這個(gè)接口。
  7. message:這里有點(diǎn)像我們?cè)?Java 中定義類,上文中我們定義了兩個(gè)類,分別是 Product 和 ProductId 兩個(gè)類。這兩個(gè)類在 service 中被使用。

message 中定義的有點(diǎn)像我們 Java 中定義的類,但是不能直接使用 Java 中的數(shù)據(jù)類型,畢竟這是 Protocol buffers,這個(gè)是和語(yǔ)言無(wú)關(guān)的,將來(lái)可以據(jù)此生成不同語(yǔ)言的代碼,這里我們可以使用的類型和我們 Java 類型之間的對(duì)應(yīng)關(guān)系如下:

圖片

另外我們?cè)?message 中定義的屬性的時(shí)候,都會(huì)給一個(gè)數(shù)字,例如 id=1,name=2 等,這個(gè)數(shù)字將來(lái)會(huì)在二進(jìn)制消息中標(biāo)識(shí)我們的字段,并且一旦我們的消息類型被使用就不應(yīng)更改,這個(gè)有點(diǎn)像序列化的感覺(jué)。

實(shí)際上,這個(gè) message 編譯后的字節(jié)內(nèi)容大概像下面這樣:

圖片

這里的標(biāo)簽中的內(nèi)容包含兩部分,字段索引和字段類型,字段索引其實(shí)就是我們上面定義的數(shù)字。

定義完成之后,接下來(lái)我們就需要使用插件來(lái)生成對(duì)應(yīng)的 Java 代碼了,插件我們?cè)谇懊嬉呀?jīng)引入了,現(xiàn)在只需要執(zhí)行了,如下圖:

圖片

注意,compile 和 compile-custom 兩個(gè)指令都需要執(zhí)行。其中 compile 用來(lái)編譯消息對(duì)象,compile-custom 則依賴消息對(duì)象,生成接口服務(wù)。

首先我們點(diǎn)擊 compile 看看生成的代碼,如下:

圖片

再看 compile-custom 生成的代碼,如下:

圖片

好了,這樣我們的準(zhǔn)備工作就算完成了。

有的小伙伴生成的代碼文件夾顏色不對(duì)勁,此時(shí)有兩種解決辦法:1.選中目標(biāo)文件夾,右鍵單擊,選擇 Mark Directory as-> Generated Sources root;2.選中工程,右鍵單擊,選擇 Maven->Reload project。推薦使用第二種方案。

3.2 grpc-server

接下來(lái)我們創(chuàng)建 grpc-server 項(xiàng)目,并使該項(xiàng)目依賴 grpc-api,然后在 grpc-server 中,提供 ProductInfo 的具體實(shí)現(xiàn):

public class ProductInfoImpl extends ProductInfoGrpc.ProductInfoImplBase {
@Override
public void addProduct(Product request, StreamObserver<ProductId> responseObserver) {
System.out.println("request.toString() = " + request.toString());
responseObserver.onNext(ProductId.newBuilder().setValue(request.getId()).build());
responseObserver.onCompleted();
}

@Override
public void getProduct(ProductId request, StreamObserver<Product> responseObserver) {
responseObserver.onNext(Product.newBuilder().setId(request.getValue()).setName("三國(guó)演義").build());
responseObserver.onCompleted();
}
}

ProductInfoGrpc.ProductInfoImplBase 是根據(jù)我們?cè)?proto 文件中定義的 service 自動(dòng)生成的,我們的 ProductInfoImpl 繼承自該類,并且提供了我們給出的方法的具體實(shí)現(xiàn)。

以 addProduct 方法為例,參數(shù) request 就是將來(lái)客戶端調(diào)用的時(shí)候傳來(lái)的 Product 對(duì)象,返回結(jié)果則通過(guò) responseObserver 來(lái)完成。我們的方法邏輯很簡(jiǎn)單,我就把參數(shù)傳來(lái)的 Product 對(duì)象打印出來(lái),然后構(gòu)建一個(gè) ProductId 對(duì)象并返回,最后調(diào)用 responseObserver.onCompleted(); 表示數(shù)據(jù)返回完畢。

剩下的 getProduct 方法邏輯就很好懂了,我這里就不再贅述了。

最后,我們?cè)侔堰@個(gè) grpc-server 項(xiàng)目啟動(dòng)起來(lái):

public class ProductInfoServer {
Server server;

public static void main(String[] args) throws IOException, InterruptedException {
ProductInfoServer server = new ProductInfoServer();
server.start();
server.blockUntilShutdown();
}

public void start() throws IOException {
int port = 50051;
server = ServerBuilder.forPort(port)
.addService(new ProductInfoImpl())
.build()
.start();
Runtime.getRuntime().addShutdownHook(new Thread(() -> {
ProductInfoServer.this.stop();
}));
}

private void stop() {
if (server != null) {
server.shutdown();
}
}

private void blockUntilShutdown() throws InterruptedException {
if (server != null) {
server.awaitTermination();
}
}
}

由于我們這里是一個(gè) JavaSE 項(xiàng)目,為了避免項(xiàng)目啟動(dòng)之后就停止,我們這里調(diào)用了 server.awaitTermination(); 方法,就是讓服務(wù)啟動(dòng)成功之后不要停止。

3.3 grpc-client

最后再來(lái)看看客戶端的調(diào)用。首先 grpc-client 項(xiàng)目也是需要依賴 grpc-api 的,然后直接進(jìn)行方法調(diào)用,如下:

public class ProductClient {
public static void main(String[] args) {
ManagedChannel channel = ManagedChannelBuilder.forAddress("localhost", 50051)
.usePlaintext()
.build();
ProductInfoGrpc.ProductInfoBlockingStub stub = ProductInfoGrpc.newBlockingStub(channel);
Product p = Product.newBuilder().setId("1")
.setPrice(399.0f)
.setName("TienChin項(xiàng)目")
.setDescription("SpringBoot+Vue3實(shí)戰(zhàn)視頻")
.build();
ProductId productId = stub.addProduct(p);
System.out.println("productId.getValue() = " + productId.getValue());
Product product = stub.getProduct(ProductId.newBuilder().setValue("99999").build());
System.out.println("product.toString() = " + product.toString());
}
}

小伙伴們看到,這里首先需要和服務(wù)端建立連接,給出服務(wù)端的地址和端口號(hào)即可,usePlaintext() 方法表示不使用 TLS 對(duì)連接進(jìn)行加密(默認(rèn)情況下會(huì)使用 TLS 對(duì)連接進(jìn)行加密),生產(chǎn)環(huán)境建議使用加密連接。

剩下的代碼就比較好懂了,創(chuàng)建 Product 對(duì)象,調(diào)用 addProduct 方法進(jìn)行添加;創(chuàng)建 ProductId 對(duì)象,調(diào)用 getProduct。Product 對(duì)象和 ProductId 對(duì)象都是根據(jù)我們?cè)?proto 中定義的 message 自動(dòng)生成的。

4. 總結(jié)

好啦,一個(gè)簡(jiǎn)單的例子,小伙伴們先對(duì) gRPC 入個(gè)門(mén),后面松哥會(huì)再整幾篇文章跟大家介紹這里邊的一些細(xì)節(jié)。

責(zé)任編輯:武曉燕 來(lái)源: 江南一點(diǎn)雨
相關(guān)推薦

2021-06-10 07:49:26

RPCgRPC模式

2015-03-24 19:48:24

2019-11-13 15:14:31

MySQL事務(wù)數(shù)據(jù)庫(kù)

2011-03-24 09:34:41

SPRING

2009-08-19 04:14:00

線性鏈表

2018-11-22 14:09:45

iOS架構(gòu)組件開(kāi)發(fā)

2009-07-14 16:02:42

JDBC例子

2020-11-09 06:38:00

ninja構(gòu)建方式構(gòu)建系統(tǒng)

2010-09-16 15:57:00

PPPoA配置

2016-03-03 14:29:15

2023-03-05 23:11:07

Go語(yǔ)言服務(wù)

2011-09-08 13:41:53

Widget

2016-09-21 12:54:10

CAAS系統(tǒng)鏡像

2022-10-31 08:27:53

Database數(shù)據(jù)數(shù)據(jù)庫(kù)

2011-04-12 14:58:23

加密解密類

2019-11-07 14:00:36

MySQL數(shù)據(jù)庫(kù)SQL

2021-11-04 10:29:01

CSS前端

2016-11-08 18:53:08

編譯器

2017-08-17 16:37:59

MySQL數(shù)據(jù)遷移

2013-04-25 09:55:21

進(jìn)程線程
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)