0****2
gRPC介紹
了解gRPC之前,就需要引入RPC的設(shè)計(jì)理念,才能更好的理解gRPC的工作原理。
遠(yuǎn)程過程調(diào)用(Remote Procedure Call,縮寫為 RPC)是一個(gè)計(jì)算機(jī)通信協(xié)議。該協(xié)議允許一臺(tái)計(jì)算上的程序調(diào)用另一臺(tái)計(jì)算機(jī)上運(yùn)行的程序,使得程序員無需再做額外的操作。如果是面向?qū)ο蟮膱鼍?,也可以稱作為遠(yuǎn)程方法調(diào)用,比如熟知的Java RMI(Remote Method Invocation)調(diào)用。
而gRPC是由Google開發(fā)的一款高性能的開源RPC框架,經(jīng)常用于微服務(wù)之間各種不同語言的程序調(diào)用函數(shù)和通信,大大的增加了微服務(wù)之間的通信效率和平臺(tái)依賴性。同時(shí)gRPC是使用Protocol buffers作為接口定義語言(IDL),可以通過編寫的proto文件來定義消息結(jié)構(gòu)體和RPC遠(yuǎn)程調(diào)用函數(shù)。
協(xié)調(diào)的接口是通過proto文件來定義的消息結(jié)構(gòu),相關(guān)文檔可以在Reference[1]中找到。再來看看gRPC的接口定義語言Protocol Buffers的工作流程圖:
結(jié)合后續(xù)的案例說明,proto文件定義好之后需要通過生成器生成對(duì)應(yīng)語言的代碼,并在項(xiàng)目中使用才可以建立gRPC調(diào)用。
03
案例說明
這里直接用綠盟星云實(shí)驗(yàn)室開源的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兩個(gè)變量,用處是明確指出包的命名空間,防止與其他語言的名稱沖突。而java_multiple_files = true 選項(xiàng)則是允許為每個(gè)生成的類,生成一個(gè)單獨(dú)的 .java 文件。
定義好了proto文件之后,就可以通過protoc或者maven的插件來生成grpc代碼,這里我用的protoc二進(jìn)制文件和插件protoc-gen-grpc來生成。
用下列兩個(gè)命令生成對(duì)應(yīng)的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",不然會(huì)顯示找不到命令。
之后會(huì)在codes文件中生成對(duì)象關(guān)系的java文件,code文件夾中生成grpc相關(guān)的UserServiceGrpc.java文件。
把生成好的Java文件添加到開發(fā)的項(xiàng)目中,并新建一個(gè)UserServiceImpl類,用來實(shí)現(xiàn)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();
}
};
}
}