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