1. 總覽
gRPC 是由 Google 開發的遠端程序呼叫 (RPC) 架構和工具集,支援各種語言、平台中立的遠端程序呼叫,可讓您使用通訊協定緩衝區 (通訊協定緩衝區) 定義服務。通訊協定緩衝區是特別強大的二進位序列化工具集和語言。然後,您就可以透過各種語言的服務定義,產生慣用的用戶端和伺服器虛設常式。
在本程式碼研究室中,您將學習如何建構以 gRPC 架構公開 API 的 Java 服務,然後編寫用戶端來使用產生的 gRPC 用戶端虛設常式。
課程內容
- 通訊協定緩衝區語言
- 如何使用 Java 實作 gRPC 服務
- 如何使用 Java 實作 gRPC 用戶端
您會如何使用這個教學課程?
針對建構 Node.js 應用程式的經驗,您會給予什麼評價?
針對建構 Go 應用程式的經驗,您會給予什麼評價?
2. 設定和需求
自修環境設定



提醒您,專案 ID 是所有 Google Cloud 專案的專屬名稱 (已經有人使用上述名稱,很抱歉對您不符!)。稍後在本程式碼研究室中會稱為 PROJECT_ID。
- 接下來,您需要在 Cloud 控制台中啟用計費功能,才能使用 Google Cloud 資源。
執行這個程式碼研究室並不會產生任何費用,如果有的話。請務必依照「清除所用資源」一節指示本節將說明如何關閉資源,這樣您就不會產生本教學課程結束後產生的費用。Google Cloud 的新使用者符合 $300 美元免費試用計畫的資格。
Google Cloud Shell
雖然這個程式碼研究室可以透過電腦操作,但在本程式碼研究室中,我們會使用 Google Cloud Shell,這是一種在 Cloud 中執行的指令列環境。
這種以 Debian 為基礎的虛擬機器,搭載各種您需要的開發工具。提供永久的 5 GB 主目錄,而且在 Google Cloud 中運作,大幅提高網路效能和驗證能力。換言之,本程式碼研究室只需要在 Chromebook 上運作即可。
- 如要透過 Cloud 控制台啟用 Cloud Shell,只要點選「啟用 Cloud Shell」 圖示
即可 (整個佈建作業只需幾分鐘的時間,操作完畢即可)。


連線至 Cloud Shell 後,您應會發現自己通過驗證,且專案已設為 PROJECT_ID。
gcloud auth list
指令輸出
Credentialed accounts: - <myaccount>@<mydomain>.com (active)
gcloud config list project
指令輸出
[core] project = <PROJECT_ID>
如因故未設定專案,請直接發出以下指令:
gcloud config set project <PROJECT_ID>
正在尋找 PROJECT_ID 嗎?查看您在設定步驟中使用的 ID,或在 Cloud 控制台資訊主頁查詢:

根據預設,Cloud Shell 也會設定一些環境變數,方便您之後執行指令。
echo $GOOGLE_CLOUD_PROJECT
指令輸出
<PROJECT_ID>
- 最後,進行預設可用區和專案設定。
gcloud config set compute/zone us-central1-f
您可以選擇各種不同的可用區。詳情請參閱「區域與可用區。
3. 建立 gRPC 服務
使用 Maven 建立新的 Java 專案:
$ mvn archetype:generate -DgroupId=com.example.grpc \ -DartifactId=grpc-hello-server \ -DarchetypeArtifactId=maven-archetype-quickstart \ -DinteractiveMode=false $ cd grpc-hello-server
新增 gRPC 定義檔案
在 gRPC 中,服務酬載 (要求和回應) 和服務作業必須在 IDL (介面定義語言) 中擷取。gRPC 使用 Protobuffer 3 語法來定義訊息酬載和作業。我們來為包含 Hello Request 和 Hello Response 的簡易 Greeting Service 建立 proto 檔案。
首先,請建立新的 proto 目錄來存放新的 proto 檔案:
$ mkdir -p src/main/proto
接著建立新的 proto 檔案 src/main/proto/GreetingService.proto。
您可以使用 vim,nano, 或 emacs 來編輯檔案:
src/main/proto/GreetingService.proto
syntax = "proto3";
package com.example.grpc;
// Request payload
message HelloRequest {
// Each message attribute is strongly typed.
// You also must assign a "tag" number.
// Each tag number is unique within the message.
string name = 1;
// This defines a strongly typed list of String
repeated string hobbies = 2;
// There are many more basics types, like Enum, Map
// See https://developers.google.com/protocol-buffers/docs/proto3
// for more information.
}
message HelloResponse {
string greeting = 1;
}
// Defining a Service, a Service can have multiple RPC operations
service GreetingService {
// Define a RPC operation
rpc greeting(HelloRequest) returns (HelloResponse);
}
新增 gRPC 依附元件和外掛程式
取得定義後,我們就能從這個檔案產生伺服器端虛設常式和用戶端虛設常式。您必須新增 gRPC 依附元件和外掛程式。
首先,請將 gRPC 依附元件新增至 pom.xml:
pom.xml
<project>
...
<dependencies>
<dependency>
<groupId>io.grpc</groupId>
<artifactId>grpc-netty-shaded</artifactId>
<version>1.24.0</version>
</dependency>
<dependency>
<groupId>io.grpc</groupId>
<artifactId>grpc-protobuf</artifactId>
<version>1.24.0</version>
</dependency>
<dependency>
<groupId>io.grpc</groupId>
<artifactId>grpc-stub</artifactId>
<version>1.24.0</version>
</dependency>
<dependency>
<groupId>javax.annotation</groupId>
<artifactId>javax.annotation-api</artifactId>
<version>1.3.2</version>
</dependency>
...
</dependencies>
...
</project>
然後新增外掛程式:
pom.xml
<project>
...
<dependencies>
...
</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.9.0:exe:${os.detected.classifier}</protocArtifact>
<pluginId>grpc-java</pluginId>
<pluginArtifact>io.grpc:protoc-gen-grpc-java:1.24.0:exe:${os.detected.classifier}</pluginArtifact>
</configuration>
<executions>
<execution>
<goals>
<goal>compile</goal>
<goal>compile-custom</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
產生存根
建構應用程式時,外掛程式會將 proto 定義轉換為 Java 程式碼。
$ mvn -DskipTests package
如要查看產生的檔案,請按照下列步驟操作:
$ find target/generated-sources
實作服務
首先,請建立新的 GreetingServiceImpl 類別來實作 greeting 作業:
src/main/java/com/example/grpc/GreetingServiceImpl.java
package com.example.grpc;
import io.grpc.stub.StreamObserver;
public class GreetingServiceImpl extends GreetingServiceGrpc.GreetingServiceImplBase {
@Override
public void greeting(GreetingServiceOuterClass.HelloRequest request,
StreamObserver<GreetingServiceOuterClass.HelloResponse> responseObserver) {
// HelloRequest has toString auto-generated.
System.out.println(request);
// You must use a builder to construct a new Protobuffer object
GreetingServiceOuterClass.HelloResponse response = GreetingServiceOuterClass.HelloResponse.newBuilder()
.setGreeting("Hello there, " + request.getName())
.build();
// Use responseObserver to send a single response back
responseObserver.onNext(response);
// When you are done, you must call onCompleted.
responseObserver.onCompleted();
}
}
實作伺服器
最後,您必須啟動伺服器來監聽通訊埠,並註冊這個服務實作項目。編輯 App 類別及其主要方法:
src/main/java/com/example/grpc/App.java
package com.example.grpc;
import io.grpc.*;
public class App
{
public static void main( String[] args ) throws Exception
{
// Create a new server to listen on port 8080
Server server = ServerBuilder.forPort(8080)
.addService(new GreetingServiceImpl())
.build();
// Start the server
server.start();
// Server threads are running in the background.
System.out.println("Server started");
// Don't exit the main thread. Wait until server is terminated.
server.awaitTermination();
}
}
最後,請執行伺服器:
$ mvn -DskipTests package exec:java -Dexec.mainClass=com.example.grpc.App ... Server Started
4. 使用服務
產生器已產生所有用戶端虛設常式。為簡化研究室,我們會使用相同的 Maven 專案,只是透過新的主要方法新增 Client 類別。
首先,點選 + 來開啟新的 Cloud Shell 工作階段,因此您無需終止伺服器:

在新工作階段中,切換至 grpc-hello-server 目錄:
$ cd grpc-hello-server
然後新增新的 Client 類別:
src/main/java/com/example/grpc/Client.java
package com.example.grpc;
import io.grpc.*;
public class Client
{
public static void main( String[] args ) throws Exception
{
// Channel is the abstraction to connect to a service endpoint
// Let's use plaintext communication because we don't have certs
final ManagedChannel channel = ManagedChannelBuilder.forTarget("localhost:8080")
.usePlaintext(true)
.build();
// It is up to the client to determine whether to block the call
// Here we create a blocking stub, but an async stub,
// or an async stub with Future are always possible.
GreetingServiceGrpc.GreetingServiceBlockingStub stub = GreetingServiceGrpc.newBlockingStub(channel);
GreetingServiceOuterClass.HelloRequest request =
GreetingServiceOuterClass.HelloRequest.newBuilder()
.setName("Ray")
.build();
// Finally, make the call using the stub
GreetingServiceOuterClass.HelloResponse response =
stub.greeting(request);
System.out.println(response);
// A Channel should be shutdown before stopping the process.
channel.shutdownNow();
}
}
最後,執行用戶端:
$ mvn -DskipTests package exec:java -Dexec.mainClass=com.example.grpc.Client ... greeting: "Hello there, Ray"
大功告成!很簡單吧?
5. 影視串流服務
你可以試試許多其他功能。舉例來說,只要在 proto 檔案中新增 stream 關鍵字至要求或回應參數 (例如:
src/main/proto/GreetingService.proto
syntax = "proto3";
package com.example.grpc;
...
// Defining a Service, a Service can have multiple RPC operations
service GreetingService {
// MODIFY HERE: Update the return to streaming return.
rpc greeting(HelloRequest) returns (stream HelloResponse);
}
更新伺服器,傳送多個回應,而非單一回應。方法是發出多次 responseObserver.onNext(...) 呼叫:
src/main/java/com/example/grpc/GreetingServiceImpl.java
package com.example.grpc;
import io.grpc.stub.StreamObserver;
public class GreetingServiceImpl extends GreetingServiceGrpc.GreetingServiceImplBase {
@Override
public void greeting(GreetingServiceOuterClass.HelloRequest request,
StreamObserver<GreetingServiceOuterClass.HelloResponse> responseObserver) {
...
// Feel free to construct different responses if you'd like.
responseObserver.onNext(response);
responseObserver.onNext(response);
responseObserver.onNext(response);
// When you are done, you must call onCompleted.
responseObserver.onCompleted();
}
}
用戶端必須使用非同步虛設常式,而非封鎖虛設常式。更新用戶端程式碼,請務必將 stub 類型更新為 GreetingServiceStub:
src/main/java/com/example/grpc/Client.java
package com.example.grpc;
import io.grpc.*;
// New import
import io.grpc.stub.*;
public class Client
{
public static void main( String[] args ) throws Exception
{
final ManagedChannel channel = ManagedChannelBuilder.forTarget("localhost:8080")
.usePlaintext(true)
.build();
// Replace the previous synchronous code with asynchronous code.
// This time use an async stub:
GreetingServiceGrpc.GreetingServiceStub stub = GreetingServiceGrpc.newStub(channel);
// Construct a request
GreetingServiceOuterClass.HelloRequest request =
GreetingServiceOuterClass.HelloRequest.newBuilder()
.setName("Ray")
.build();
// Make an Asynchronous call. Listen to responses w/ StreamObserver
stub.greeting(request, new StreamObserver<GreetingServiceOuterClass.HelloResponse>() {
public void onNext(GreetingServiceOuterClass.HelloResponse response) {
System.out.println(response);
}
public void onError(Throwable t) {
}
public void onCompleted() {
// Typically you'll shutdown the channel somewhere else.
// But for the purpose of the lab, we are only making a single
// request. We'll shutdown as soon as this request is done.
channel.shutdownNow();
}
});
}
}
重新建構應用程式:
$ mvn -DskipTests package
請在專屬的 Cloud Shell 工作階段中,重新啟動伺服器和用戶端。
如何啟動伺服器:
$ mvn exec:java -Dexec.mainClass=com.example.grpc.App ... Server Started
如何啟動用戶端:
$ mvn exec:java -Dexec.mainClass=com.example.grpc.Client ... greeting: "Hello there, Ray" greeting: "Hello there, Ray" greeting: "Hello there, Ray"
6. 恭喜!
本文涵蓋內容:
- 通訊協定緩衝區語言
- 如何使用 Java 實作 gRPC 伺服器
- 如何使用 Java 實作 gRPC 用戶端
後續步驟:
- 進一步瞭解 gRPC Java
- 查看更多 GitHub 上的 gRPC Java 範例
- 瞭解在 gRPC 中串流。
- 進一步瞭解從 gRPC 到 REST 轉碼
請提供您寶貴的意見
- 請花點時間完成簡短的問卷調查