Spring Boot 使用 gRPC 輕鬆調用遠程方法

Spring Boot 使用 gRPC 輕鬆調用遠程方法

gRPC 簡介

gRPC 是一個現代開源的高性能 RPC 框架,可以在任何環境下運行。它可以有效地將數據中心內和跨數據中心的服務與可插拔支持進行負載均衡、跟蹤、健康檢查和認證。它也適用於分佈式計算,將不同設備、移動應用程序和瀏覽器連接到後端服務。

主要使用場景:

  • 在微服務架構中有效地連接多個服務
  • 將移動設備、瀏覽器客戶端連接到後端服務
  • 生成高效的客戶端庫

核心功能:

  • 10 種語言的客戶端庫支持
  • 高效、簡單的服務定義框架
  • 基於 http/2 傳輸的雙向流式傳輸
  • 可插拔的認證、跟蹤、負載均衡和健康檢查
Spring Boot 使用 gRPC 輕鬆調用遠程方法

Spring Boot 快速集成 gRPC

1、獲取 spring-boot-starter-grpc 源碼

git clone https://github.com/ChinaSilence/spring-boot-starter-grpc.git

2、安裝到本地 Maven 倉庫

mvn install

3、在 Spring Boot 工程中添加依賴

<dependency>
<groupid>com.anoyi
<artifactid>spring-boot-starter-grpc
<version>1.0.0.RELEASE

4、gRPC 使用說明

4.1 參數配置說明

  • spring.grpc.enable 是否啟用 gRPC 服務端,默認 false
  • spring.grpc.port 監聽的端口號
  • spring.grpc.remote-servers 供客戶端調用的服務端列表

4.2 示例:gRPC 服務端,在 application.yml 中添加配置

spring:
grpc: enable: true
port: 6565

4.3 示例:gRPC 客戶端,在 application.yml 中添加配置

spring: grpc: remote-servers: - host: localhost
port: 6565 - host: 192.168.0.3
port: 6565

4.4 遠程服務調用

遠程服務調用需要知道遠程服務的:地址、端口號、服務類、類方法、方法參數,該 starter 定義了 GrpcRequest 和 GrpcResponse。

public class GrpcRequest {
/**
* service 類名
*/
private String beanName;
/**
* service 方法名
*/
private String methodName;
/**
* service 方法參數
*/
private Object[] args;
// 略 setter / getter...
}

public class GrpcResponse {
/**
* 響應狀態:0 - 成功, 1 - 失敗
*/
private int status;

/**
* 返回結果
*/
private Object result;
// 略 setter / getter...
}

4.4.1 示例:服務端提供服務,與單體 Spring Boot 無差別,即單體 Spring Boot 應用可以無縫集成

@Service
public class HelloService{
public String sayHello() {
return "Hello";
}
public String say(String words){
return "Hello " + words;
}
}

4.4.2 【註解方式】示例:客戶端調用服務

import org.springframework.grpc.annotation.GrpcService;
/**
* 使用 @GprcService 註解定義遠程服務,server 指定遠程服務名,必須在 application.yml 中定義才能使用
* 方法名 、參數 、 返回結果 必須與服務提供方一致
*/
@GrpcService(server = "localhost")
public interface HelloService {
public String sayHello();
public String say(String words);
}

4.4.3 【非註解方式】示例:客戶端調用服務

 public void test(){ // 構建請求體
GrpcRequest grpcRequest = new GrpcRequest();

grpcRequest.setServiceBeanName("helloService"); // 無參方法調用
grpcRequest.setServiceMethodName("sayHello");
try { // 此處服務提供方需要在配置文件中定義,否則無法調用
GrpcResponse response = GrpcClient.connect("localhost").handle(grpcRequest); if (response.getStatus() == GrpcResponseStatus.SUCCESS.getCode()){
System.out.println(response.getResult());
}
} catch (Exception e) {
e.printStackTrace();
} // 有參方法調用
grpcRequest.setServiceMethodName("say");
Object[] args = {"hello"};
grpcRequest.setArgs(args);
try { // 此處服務提供方需要在配置文件中定義,否則無法調用
GrpcResponse response = GrpcClient.connect("localhost").handle(grpcRequest); if (response.getStatus() == GrpcResponseStatus.SUCCESS.getCode()){
System.out.println(response.getResult());
}
} catch (Exception e) {
e.printStackTrace();
}
}

4.4.4 【測試使用】示例:為方便調試,通過原生方式調用遠程服務,無需依賴 Spring Boot

import com.alibaba.fastjson.JSON;
import com.anoyi.rpc.CommonServiceGrpc;
import com.anoyi.rpc.GrpcService;
import io.grpc.ManagedChannel;
import io.grpc.ManagedChannelBuilder;
import org.springframework.grpc.service.GrpcRequest;
import java.util.concurrent.TimeUnit;

public class GrpcClient {
private final ManagedChannel channel;
private final CommonServiceGrpc.CommonServiceBlockingStub blockingStub;

public GrpcClient(String host, int port) { this(ManagedChannelBuilder.forAddress(host, port).usePlaintext().build());
}
private GrpcClient(ManagedChannel channel) {
this.channel = channel;
blockingStub = CommonServiceGrpc.newBlockingStub(channel);

}

public static void main(String[] args) throws Exception {
GrpcClient client = new GrpcClient("localhost", 6565);
try { for (int i = 0; i < 100; i++) {
String words = "world - " + i;
client.say(words);
}
} finally {
client.shutdown();
}
}

private void shutdown() throws InterruptedException {
channel.shutdown().awaitTermination(5, TimeUnit.SECONDS);
}

private void say(String words) {
GrpcRequest grpcRequest = new GrpcRequest();
grpcRequest.setBeanName("helloService");
grpcRequest.setMethodName("say");
Object[] params = {words};
grpcRequest.setArgs(params);
System.out.println("遠程調用 " + grpcRequest.getServiceBeanName() + "." + grpcRequest.getServiceMethodName() + " ");
byte[] bytes = ProtobufUtils.serialize(grpcRequest);
GrpcService.Request request = GrpcService.Request.newBuilder().setRequest(ByteString.copyFrom(bytes)).build();
GrpcService.Response response = blockingStub.handle(request);
System.out.println("遠程調用結果: " + response.getReponse());
}
}


分享到:


相關文章: