gRPC之java语言的简单Demo
最近由于項目需要,就簡單看了下gRPC入門,使用起來挺簡單的。這里就順便記錄一下,便于后面回顧。
RPC是什么
說到RPC(Remote Process Communication,遠(yuǎn)程過程調(diào)用)就不得不說到進程間通信(Inter-process Communication,簡稱IPC),IPC是指多個進程之間傳送數(shù)據(jù)或信號的一些技術(shù)或方法。
而IPC又分為本地過程調(diào)用(LPC)和遠(yuǎn)程過程調(diào)用(RPC),這兩者的區(qū)別就是 LPC的調(diào)用可以共享內(nèi)存空間,比較方便;而RPC的調(diào)用雙方則不在同一個主機中,無法像LPC那樣方便。
說到底,RPC就是在本地來 調(diào)用遠(yuǎn)程的方法。而RPC框架要做的就是 讓遠(yuǎn)程調(diào)用 像本地調(diào)用一樣方便,而這個調(diào)用過程則是RPC框架需要做的工作。這個工作涉及到大概 兩個方面:序列化協(xié)議 和 傳輸協(xié)議。
1、常見的序列化協(xié)議有: 基于文本(text)的:XML、JSON 基于二進制(binary)的: Protocol Buffer、Thrift等 2、常見的傳輸協(xié)議有: 傳輸層的: TCP(基于Socket)、UDP 應(yīng)用層的:HTTP1.1、HTTP2.0
而RPC框架中,通常使用的序列化協(xié)議包括Protocol Buffer、Thrift等,傳輸協(xié)議則常用TCP、HTTP2.0等。
更多的內(nèi)容可以參考博客:【RPC簡介及框架選擇】
gRPC框架
上面簡單介紹了RPC機制的作用,現(xiàn)如今已經(jīng)出現(xiàn)了許多優(yōu)秀的RPC框架,比如:gRPC、Dubbo、Thrift等。這些框架在 序列化協(xié)議和傳輸協(xié)議兩部分都有不同的選擇,各有優(yōu)劣。不過,沒必要全部都去學(xué)習(xí)一遍,可以簡單嘗試一種,大概了解運行機制即可。
下面是以gRPC的簡單使用為例,了解gRPC的運行過程和用法。
gRPC使用的序列化協(xié)議是 Protocol Buffer,使用的傳輸協(xié)議是 HTTP2.0協(xié)議。
需要清楚的是,
gRPC的通信方式需要先確定好proto文件,這個proto文件中定義了遠(yuǎn)程api的具體服務(wù)接口、api方法的參數(shù)類型/返回值類型;
然后,將該proto文件編譯為 java類文件,這些類文件包含的就是 client端 和 server端都遵循的 遠(yuǎn)程調(diào)用api的定義內(nèi)容。
接著,client端 和 server端按照gRPC框架的方式來進行通信即可。
gRPC的java示例
具體步驟如下【參考源碼】:
1、創(chuàng)建一個maven項目,創(chuàng)建src/main/proto目錄,在其中添加定義好的遠(yuǎn)程API接口hello.proto文件,如下:
// 使用該proto文件可以定義交互的服務(wù)接口,基于該文件編譯成的源文件可以分別復(fù)制到 client端和server端,便于兩者使用
?
syntax = "proto3"; // 定義語法類型
?
package hello; // 定義作用域
option java_multiple_files = false; // 表示下面的message不需要編譯成多個java文件
option java_outer_classname = "HelloMessage"; // 表示下面的message編譯成的java類文件的名字
option java_package = "grpc"; //指定該proto文件編譯成的java源文件的包名
?
service Hello { // 定義服務(wù)
rpc sayHello(HelloRequest) returns(HelloResponse) {}
}
?
message HelloRequest { // 定義請求的消息體
string name = 1;
}
?
message HelloResponse { // 定義回復(fù)的消息體
string message = 1;
}
2、在pom.xml文件中添加gRPC依賴與插件,參考grpc-java倉庫,如下:
依賴為:
<dependencies>
<dependency>
<groupId>io.grpc</groupId>
<artifactId>grpc-netty-shaded</artifactId>
<version>1.31.1</version>
</dependency>
<dependency>
<groupId>io.grpc</groupId>
<artifactId>grpc-protobuf</artifactId>
<version>1.31.1</version>
</dependency>
<dependency>
<groupId>io.grpc</groupId>
<artifactId>grpc-stub</artifactId>
<version>1.31.1</version>
</dependency>
<dependency>
<groupId>org.apache.tomcat</groupId>
<artifactId>annotations-api</artifactId>
<version>6.0.53</version>
<scope>provided</scope>
</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.31.1:exe:${os.detected.classifier}</pluginArtifact>
</configuration>
<executions>
<execution>
<goals>
<goal>compile</goal>
<goal>compile-custom</goal>
</goals>
</execution>
</executions>
</plugin>
?
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.1</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
<encoding>utf-8</encoding>
</configuration>
</plugin>
?
</plugins>
</build>
3、執(zhí)行mvn clean compile命令,然后在生成的target/generated-sources/ptotobuf文件夾中找到服務(wù)接口對應(yīng)的類文件 和 接口參數(shù)/返回值對應(yīng)的類文件。
將這兩個文件分別復(fù)制到client端 和 server端的java源文件中。
4、編寫server端代碼,如下:
public class ServerDemo {
?
// 定義一個Server對象,監(jiān)聽端口來獲取rpc請求,以進行下面的處理
private Server server;
?
//使用main方法來測試server端
public static void main(String[] args) throws IOException, InterruptedException {
?
final ServerDemo serverDemo = new ServerDemo();
?
//啟動server
serverDemo.start();
?
//block 一直到退出程序
serverDemo.blockUntilShutdown();
}
?
/**
* 啟動一個Server實例,監(jiān)聽client端的請求并處理
* @throws IOException
*/
private void start() throws IOException {
?
//server運行在的端口號
int port = 50051;
?
// 給server添加監(jiān)聽端口號,添加 包含業(yè)務(wù)處理邏輯的類,然后啟動
server = ServerBuilder.forPort(port)
.addService(new HelloImpl())
.build()
.start();
?
}
?
/**
* 阻塞server直到關(guān)閉程序
* @throws InterruptedException
*/
private void blockUntilShutdown() throws InterruptedException {
?
if (server != null) {
server.awaitTermination();
}
?
}
?
?
/**
* proto文件被編譯后,在生成的HelloGrpc的抽象內(nèi)部類HelloImplBase中包含了 proto中定義的服務(wù)接口的簡單實現(xiàn)
* 該HelloImpl類需要重寫這些方法,添加需要的處理邏輯
*/
static class HelloImpl extends HelloGrpc.HelloImplBase {
?
// proto文件中的sayHello服務(wù)接口被編譯后,在生成的HelloGrpc的抽象內(nèi)部類HelloImplBase中有一個簡單的實現(xiàn)
// 因此,在server端需要重寫這個方法,添加上相應(yīng)的邏輯
@Override
public void sayHello(HelloMessage.HelloRequest req, StreamObserver<HelloMessage.HelloResponse> responseObserver) {
?
HelloMessage.HelloResponse reply = HelloMessage.HelloResponse.newBuilder().setMessage("(server端的sayHello()方法處理結(jié)果) Hello," + req.getName()).build();
?
?
// 調(diào)用onNext()方法來通知gRPC框架把reply 從server端 發(fā)送回 client端
responseObserver.onNext(reply);
?
// 表示完成調(diào)用
responseObserver.onCompleted();
}
}
?
}
5、編寫client端代碼,如下:
public class ClientDemo {
?
//使用main方法來測試client端
public static void main(String[] args) throws Exception {
?
ClientDemo clientDemo = new ClientDemo();
?
try {
?
//基于gRPC遠(yuǎn)程調(diào)用對應(yīng)的方法
clientDemo.remoteCall("【zhongyuan】");
?
} finally {
?
}
}
?
/**
* 基于gRPC框架的使用步驟,進行遠(yuǎn)程調(diào)用
* @param name
*/
public void remoteCall(String name) {
?
HelloMessage.HelloRequest request = HelloMessage.HelloRequest.newBuilder().setName(name).build();
HelloMessage.HelloResponse response;
?
try {
?
// 基于訪問地址 創(chuàng)建通道
Channel channel = ManagedChannelBuilder.forAddress("localhost", 50051).usePlaintext().build();
?
// 利用通道 創(chuàng)建一個樁(Stub)對象
HelloGrpc.HelloBlockingStub blockingStub = HelloGrpc.newBlockingStub(channel);
?
//通過樁對象來調(diào)用遠(yuǎn)程方法
response = blockingStub.sayHello(request);
?
} catch (StatusRuntimeException e) {
return;
}
?
System.out.println("client端遠(yuǎn)程調(diào)用sayHello()的結(jié)果為:
" + response.getMessage());
}
?
}
6、接下來,先運行server端main()函數(shù),再運行client端的main()函數(shù),即可測試rpc遠(yuǎn)程調(diào)用結(jié)果,如下:
源碼詳見:https://github.com/zhongyuanzhao000/gRPC-demo
參考:
grpc官網(wǎng):https://grpc.io/docs/languages/java/quickstart/
grpc官方文檔中文版:http://doc.oschina.net/grpc?t=60134
grpc-java倉庫:https://github.com/grpc/grpc-java
博客:
https://blog.csdn.net/sunsun314/article/details/73780169
https://blog.csdn.net/m0_38001814/article/details/108229637
總結(jié)
以上是生活随笔為你收集整理的gRPC之java语言的简单Demo的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 错误:不能继续进行下一步操作 openf
- 下一篇: 1. 决策树(Decision Tree