0****2
gRPC介紹
了解gRPC之前,就需要引入RPC的設計理念,才能更好的理解gRPC的工作原理。
遠程過程調用(Remote Procedure Call,縮寫為 RPC)是一個計算機通信協議。該協議允許一臺計算上的程序調用另一臺計算機上運行的程序,使得程序員無需再做額外的操作。如果是面向對象的場景,也可以稱作為遠程方法調用,比如熟知的Java RMI(Remote Method Invocation)調用。
而gRPC是由Google開發的一款高性能的開源RPC框架,經常用于微服務之間各種不同語言的程序調用函數和通信,大大的增加了微服務之間的通信效率和平臺依賴性。同時gRPC是使用Protocol buffers作為接口定義語言(IDL),可以通過編寫的proto文件來定義消息結構體和RPC遠程調用函數。
協調的接口是通過proto文件來定義的消息結構,相關文檔可以在Reference[1]中找到。再來看看gRPC的接口定義語言Protocol Buffers的工作流程圖:
結合后續的案例說明,proto文件定義好之后需要通過生成器生成對應語言的代碼,并在項目中使用才可以建立gRPC調用。
03
案例說明
這里直接用綠盟星云實驗室開源的gRPC靶場來研究:https://github.com/snailll/gRPCDemo
首先直接看看他的user.proto是如何定義的
syntax = "proto3";
package protocol;
option go_package = "protocol";
option java_multiple_files = true;
option java_package = "com.demo.shell.protocol";
message User {
int32 userId = 1;
string username = 2;
sint32 age = 3;
string name = 4;
}
service UserService {
rpc getUser (User) returns (User) {}
rpc getUsers (User) returns (stream User) {}
rpc saveUsers (stream User) returns (User) {}
}
可以看到文件中定義了go_package和java_package兩個變量,用處是明確指出包的命名空間,防止與其他語言的名稱沖突。而java_multiple_files = true 選項則是允許為每個生成的類,生成一個單獨的 .java 文件。
定義好了proto文件之后,就可以通過protoc或者maven的插件來生成grpc代碼,這里我用的protoc二進制文件和插件protoc-gen-grpc來生成。
用下列兩個命令生成對應的Java代碼文件:
protoc -I=. --java_out=./codes/ user.proto
protoc.exe --plugin=protoc-gen-grpc-java.exe --grpc-java_out=./code --proto_path=. user.proto
這里的grpc插件一定要重新命名為"protoc-gen-grpc-java",不然會顯示找不到命令。
之后會在codes文件中生成對象關系的java文件,code文件夾中生成grpc相關的UserServiceGrpc.java文件。
把生成好的Java文件添加到開發的項目中,并新建一個UserServiceImpl類,用來實現grpc的方法。
package com.demo.shell.service;
import com.demo.shell.protocol.User;
import com.demo.shell.protocol.UserServiceGrpc;
import io.grpc.stub.StreamObserver;
/**
* @author demo
* @date 2022/11/27
*/
public class UserServiceImpl extends UserServiceGrpc.UserServiceImplBase {
@Override
public void getUser(User request, StreamObserver< User > responseObserver) {
System.out.println(request);
User user = User.newBuilder()
.setName("response name")
.build();
responseObserver.onNext(user);
responseObserver.onCompleted();
}
@Override
public void getUsers(User request, StreamObserver< User > responseObserver) {
System.out.println("get users");
System.out.println(request);
User user = User.newBuilder()
.setName("user1")
.build();
User user2 = User.newBuilder()
.setName("user2")
.build();
responseObserver.onNext(user);
responseObserver.onNext(user2);
responseObserver.onCompleted();
}
@Override
public StreamObserver< User > saveUsers(StreamObserver< User > responseObserver) {
return new StreamObserver< User >() {
@Override
public void onNext(User user) {
System.out.println("get saveUsers list ---- >");
System.out.println(user);
}
@Override
public void onError(Throwable throwable) {
System.out.println("saveUsers error " + throwable.getMessage());
}
@Override
public void onCompleted() {
User user = User.newBuilder()
.setName("saveUsers user1")
.build();
responseObserver.onNext(user);
responseObserver.onCompleted();
}
};
}
}