1.什么是GRPC?
gRPC?是一個高性能、開源、通用的RPC框架,由Google推出,基于HTTP2協議標準設計開發,默認采用Protocol Buffers數據序列化協議,支持多種開發語言。gRPC提供了一種簡單的方法來精確的定義服務,并且為客戶端和服務端自動生成可靠的功能庫。 在gRPC客戶端可以直接調用不同服務器上的遠程程序,使用姿勢看起來就像調用本地程序一樣,很容易去構建分布式應用和服務。和很多RPC系統一樣,服務端負責實現定義好的接口并處理客戶端的請求,客戶端根據接口描述直接調用需要的服務。客戶端和服務端可以分別使用gRPC支持的不同語言實現。
主要特性
- 強大的IDLgRPC使用ProtoBuf來定義服務,ProtoBuf是由Google開發的一種數據序列化協議(類似于XML、JSON、hessian)。ProtoBuf能夠將數據進行序列化,并廣泛應用在數據存儲、通信協議等方面。
- 多語言支持gRPC支持多種語言,并能夠基于語言自動生成客戶端和服務端功能庫。目前已提供了C版本grpc、Java版本grpc-java 和 Go版本grpc-go,其它語言的版本正在積極開發中,其中,grpc支持C、C++、Node.js、Python、Ruby、Objective-C、PHP和C#等語言,grpc-java已經支持Android開發。
- HTTP2gRPC基于HTTP2標準設計,所以相對于其他RPC框架,gRPC帶來了更多強大功能,如雙向流、頭部壓縮、多復用請求等。這些功能給移動設備帶來重大益處,如節省帶寬、降低TCP鏈接次數、節省CPU使用和延長電池壽命等。同時,gRPC還能夠提高了云端服務和Web應用的性能。gRPC既能夠在客戶端應用,也能夠在服務器端應用,從而以透明的方式實現客戶端和服務器端的通信和簡化通信系統的構建。
?
2.代碼工程
我們建議將您的項目分為2至3個不同的模塊。
- grpc-api 項目?包含原始 protobuf 文件并生成 java model 和 service 類。 你可能會在不同的項目中會共享這個部分。
- grpc-Server 項目?包含項目的業務實現,并使用上面的 Interface 項目作為依賴項。
- grpc-Client 項目(可選,可能很多) 任何使用預生成的 stub 來訪問服務器的客戶端項目。
實驗目的
定義了一個Hello Service,客戶端發送包含字符串名字的請求,服務端返回Hello消息。
grpc-api
pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><parent><artifactId>grpc</artifactId><groupId>com.et</groupId><version>1.0-SNAPSHOT</version><relativePath>../pom.xml</relativePath></parent><modelVersion>4.0.0</modelVersion><artifactId>grpc-api</artifactId><properties><maven.compiler.source>8</maven.compiler.source><maven.compiler.target>8</maven.compiler.target><protobuf.version>3.23.4</protobuf.version><protobuf-plugin.version>0.6.1</protobuf-plugin.version><grpc.version>1.58.0</grpc.version></properties><dependencies><dependency><groupId>io.grpc</groupId><artifactId>grpc-stub</artifactId><version>${grpc.version}</version></dependency><dependency><groupId>io.grpc</groupId><artifactId>grpc-protobuf</artifactId><version>${grpc.version}</version></dependency><dependency><!-- Java 9+ compatibility - Do NOT update to 2.0.0 --><groupId>jakarta.annotation</groupId><artifactId>jakarta.annotation-api</artifactId><version>1.3.5</version><optional>true</optional></dependency></dependencies><build><extensions><extension><groupId>kr.motd.maven</groupId><artifactId>os-maven-plugin</artifactId><version>1.7.0</version></extension></extensions><plugins><plugin><groupId>org.xolstice.maven.plugins</groupId><artifactId>protobuf-maven-plugin</artifactId><version>${protobuf-plugin.version}</version><configuration><protocArtifact>com.google.protobuf:protoc:${protobuf.version}:exe:${os.detected.classifier}</protocArtifact><pluginId>grpc-java</pluginId><pluginArtifact>io.grpc:protoc-gen-grpc-java:${grpc.version}:exe:${os.detected.classifier}</pluginArtifact></configuration><executions><execution><goals><goal>compile</goal><goal>compile-custom</goal></goals></execution></executions></plugin></plugins></build>
</project>
proto
將您的 protobuf 定義/.proto
文件放入src/main/proto
。 有關編寫 protobuf 文件的信息,請參閱官方的?protobuf 文檔。 您的?.proto
?文件跟如下的示例類似:
syntax = "proto3";package net.devh.boot.grpc.example;option java_multiple_files = true;
option java_package = "com.et.grpc.api.protobuf.lib";
option java_outer_classname = "HelloWorldProto";// The greeting service definition.
service MyService {// Sends a greetingrpc SayHello (HelloRequest) returns (HelloReply) {}
}// The request message containing the user's name.
message HelloRequest {string name = 1;
}// The response message containing the greetings
message HelloReply {string message = 1;
}
生成文件,源碼在target/generated-sources/protobuf
mvn protobuf:compile mvn protobuf:compile-custom
最后打包給server和client引用
grpc-server
protoc-gen-grpc-java
?插件為你的每個 grpc 服務生成一個類。 例如:MyServiceGrpc
?的?MyService
?是 proto 文件中的 grpc 服務名稱。 這個類 包含您需要擴展的客戶端 stub 和服務端的?ImplicBase
。 在這之后,你還有四個步驟:
- 請確保您的?
MyServiceImp
?實現了?MyServiceGrpc.MyServiceImpBase
- 將?
@GrpcService
?注解添加到您的?MyServiceImp
?類上 - 請確保?
MyServiceImplic
?已添加到您的應用程序上下文中。- 通過在您的?
@Configuration
?類中創建?@Bean
- 或者將其放置在 spring 的自動檢測到路徑中(例如在您
Main
類的相同或子包中)
- 通過在您的?
- 實現 grpc 服務方法。
pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><parent><artifactId>grpc</artifactId><groupId>com.et</groupId><version>1.0-SNAPSHOT</version><relativePath>../pom.xml</relativePath></parent><modelVersion>4.0.0</modelVersion><artifactId>grpc-server</artifactId><properties><maven.compiler.source>8</maven.compiler.source><maven.compiler.target>8</maven.compiler.target></properties><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-autoconfigure</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency><dependency><groupId>net.devh</groupId><artifactId>grpc-server-spring-boot-starter</artifactId><version>${grpc.version}</version></dependency><dependency><groupId>com.et</groupId><artifactId>grpc-api</artifactId><version>1.0-SNAPSHOT</version></dependency></dependencies><build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId></plugin></plugins></build>
</project>
service
/** Copyright (c) 2016-2023 The gRPC-Spring Authors** Licensed under the Apache License, Version 2.0 (the "License");* you may not use this file except in compliance with the License.* You may obtain a copy of the License at** http://www.apache.org/licenses/LICENSE-2.0** Unless required by applicable law or agreed to in writing, software* distributed under the License is distributed on an "AS IS" BASIS,* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.* See the License for the specific language governing permissions and* limitations under the License.*/package com.et.grpc.server;import com.et.grpc.api.protobuf.lib.HelloReply;
import com.et.grpc.api.protobuf.lib.HelloRequest;
import com.et.grpc.api.protobuf.lib.MyServiceGrpc;
import io.grpc.stub.StreamObserver;import net.devh.boot.grpc.server.service.GrpcService;/*** @author Michael (yidongnan@gmail.com)* @since 2016/11/8*/@GrpcService
public class GrpcServerService extends MyServiceGrpc.MyServiceImplBase {@Overridepublic void sayHello(HelloRequest req, StreamObserver<HelloReply> responseObserver) {HelloReply reply = HelloReply.newBuilder().setMessage("Hello ==> " + req.getName()).build();responseObserver.onNext(reply);responseObserver.onCompleted();}}
application.yaml
spring:application:name: local-grpc-server
grpc:server:port: 9898
grpc-client
以下列表包含您可能在客戶端使用到的的所有功能。 如果您不想使用任何高級功能,那么前兩個元素可能都是您需要使用的。
- @GrpcClient: 在需要注入的客戶端的字段或者 setter 方法上這個注解。 支持?
Channel
和各種類型的?Stub
。 請不要將?@GrpcClient
?與?@Autowireed
?或?@Inject
?一起使用。 目前,它不支持構造函數和?@Bean
?方法參數。 這種情況請查看后面?@GrpcClientBean
?的使用文檔。?注意:?同一應用程序提供的服務只能在 ` ApplicationStartedEvent?之后訪問/調用。 連接到外部服務的 Stubs 可以提前使用;從?
@PostConstruct?/?
初始化Bean#afterPropertiesSet()` 開始。 - @GrpcClientBean: 注解會把使用?
@GrpcClient
?注解的類型注冊到 Spring Context 中,方便?@Autowired
?和?@Qualifier
?的使用。 這個注解可以重復添加到您的?@Configuration
?類中。 - Channel: Channel 是單個地址的連接池。 目標服務器可能是多個 gRPC 服務。 該地址將使用?
NameResolver
?做解析,最終它可能會指向一批固定數量或動態數量的服務端。 - ManagedChannel: ManagedChannel 是 Channel 的一種特殊變體,因為它允許對連接池進行管理操作,例如將其關閉。
- NameResolver、?NameResolver.Factory: 一個用于將地址解析為
SocketAddress
?列表的類 ,當與先前列出的服務端連表連接失敗或通道空閑時,地址將會重新做解析。 參閱?Configuration -> Choosing the Target。 - ClientInterceptor: 在每個?
Channel
?處理之前攔截它們。 可以用于日志、監測、元數據處理和請求/響應的重寫。 grpc-spring-boot-starter 將自動接收所有帶有?@GrpcGlobalClientInterceptor?注解以及手動注冊在GlobalClientInterceptorRegistry?上的客戶攔截器。 參閱?Configuration -> ClientInterceptor。 - CallCredentials: 管理身份驗證的組件。 它可以用于存儲憑據和會話令牌。 它還可以用來身份驗證,并且使用返回的令牌(例如 OAuth) 來授權實際請求。 除此之外,如果令牌過期并且重新發送請求,它可以續簽令牌。 如果您的應用程序上下文中只存在一個?
CallCredentials
?bean,那么 spring 將會自動將其附加到Stub
(?非?Channel
?)。?CallCredentialsHelper工具類可以幫助您創建常用的?CallCredentials
?類型和相關的StubTransformer
。 - StubFactory: 一個用于從?
Channel
?創建特定?Stub
?的工廠。 可以注冊多個?StubFactory
,以支持不同類型的 stub。 參閱?Configuration -> StubFactory。 - StubTransformer: 所有客戶端的?
Stub
?的注入之前應用的轉換器。 參閱?Configuration -> StubTransformer。
pom.xml
/** Copyright (c) 2016-2023 The gRPC-Spring Authors** Licensed under the Apache License, Version 2.0 (the "License");* you may not use this file except in compliance with the License.* You may obtain a copy of the License at** http://www.apache.org/licenses/LICENSE-2.0** Unless required by applicable law or agreed to in writing, software* distributed under the License is distributed on an "AS IS" BASIS,* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.* See the License for the specific language governing permissions and* limitations under the License.*/package com.et.grpc.client;import com.et.grpc.api.protobuf.lib.HelloReply;
import com.et.grpc.api.protobuf.lib.HelloRequest;
import com.et.grpc.api.protobuf.lib.MyServiceGrpc;
import org.springframework.stereotype.Service;import io.grpc.StatusRuntimeException;
import net.devh.boot.grpc.client.inject.GrpcClient;/*** @author Michael (yidongnan@gmail.com)* @since 2016/11/8*/
@Service
public class GrpcClientService {@GrpcClient("local-grpc-server")// @GrpcClient("cloud-grpc-server")private MyServiceGrpc.MyServiceBlockingStub myServiceStub;public String sendMessage(final String name) {try {final HelloReply response = this.myServiceStub.sayHello(HelloRequest.newBuilder().setName(name).build());return response.getMessage();} catch (final StatusRuntimeException e) {return "FAILED with " + e.getStatus().getCode().name();}}}
controller
/** Copyright (c) 2016-2023 The gRPC-Spring Authors** Licensed under the Apache License, Version 2.0 (the "License");* you may not use this file except in compliance with the License.* You may obtain a copy of the License at** http://www.apache.org/licenses/LICENSE-2.0** Unless required by applicable law or agreed to in writing, software* distributed under the License is distributed on an "AS IS" BASIS,* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.* See the License for the specific language governing permissions and* limitations under the License.*/package com.et.grpc.client;import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;/*** @author Michael (yidongnan@gmail.com)* @since 2016/12/4*/
@RestController
public class GrpcClientController {@Autowiredprivate GrpcClientService grpcClientService;@RequestMapping("/")public String printMessage(@RequestParam(defaultValue = "Michael") String name) {return grpcClientService.sendMessage(name);}}
application.yaml
server:port: 8088
spring:application:name: local-grpc-clientgrpc:client:local-grpc-server:address: 'static://127.0.0.1:9898'enableKeepAlive: truekeepAliveWithoutCalls: truenegotiationType: plaintext
3.測試
- 啟動服務端
- 啟動客戶端
- 調用服務http://127.0.0.1:8088/
測試服務
您可以通過運行?gRPCurl?命令來測試您的應用程序是否正常運行:
grpcurl --plaintext localhost:9898 list
grpcurl --plaintext localhost:9898 list net.devh.boot.grpc.example.MyService
# Linux (Static content)
grpcurl --plaintext -d '{"name": "test"}' localhost:9898 net.devh.boot.grpc.example.MyService/sayHello
# Windows or Linux (dynamic content)
grpcurl --plaintext -d "{\"name\": \"test\"}" localhost:9898 net.devh.boot.grpc.example.MyService/sayHello
gRPCurl
?的示例命令輸出以及其他信息請參考此?文檔?。
4.引用
- 入門指南 | grpc-spring-boot-starter