gRPC是一個高性能、開源、通用的RPC框架,面向移動和HTTP/2設計。gRPC 默認使用 protocol buffers,這是 Google 開源的一套成熟的結構數據序列化機制。
Protocol Buffers 是一種輕便高效的結構化數據存儲格式,可以用於結構化數據串行化,或者說序列化。它很適合做數據存儲或 RPC 數據交換格式。可用於通訊協議、數據存儲等領域的語言無關、平臺無關、可擴展的序列化結構數據格式。
簡介
本文只是根據gRPC相關資料文檔編寫的Java Spring Boot 與 Golang 語言相關調用的示例。
詳細內容
編寫proto文件
使用proto3語法。文件user_provider.proto
。
需要使用proto文件,來自動生成不同語言的相關接口、類、對象等。
// user service provider
// proto語法版本
syntax = "proto3";
// 可選參數 設置java package
option java_package = "cn.lpe234.grpc.grpcdemo.grpc";
// 定義對外暴露的服務
service UserProvider {
// 根據用戶id獲取用戶信息的服務(具體服務/函數)
rpc getByUserId(UserIdRequest) returns (UserVoReplay) {}
}
// 請求
message UserIdRequest {
uint64 id = 1; // 用戶id 類型爲Long
}
// 響應
message UserVoReplay {
uint64 id = 1; // 用戶id
string username = 2; // 用戶名稱
}
Java Spring Boot 相關
使用Maven作爲項目的依賴管理及編譯構建工具。當前使用Maven插件,在編譯時根據proto文件自動生成服務編寫時所需的Class類。
需要將*.proto
放置在 xxProject/src/main/proto
文件夾下,才能被插件讀取到。也就是proto
文件夾需要跟java
、resources
文件夾並列才行(或許可通過修改配置信息修改proto文件存儲位置,未做深究~)。
Maven配置
項目精簡的pxm.xml配置文件。
<!-- grpc 依賴版本 -->
<properties>
<grpc.version>1.14.0</grpc.version>
</properties>
<!-- grpc 依賴jar包 -->
<dependencies>
<dependency>
<groupId>io.grpc</groupId>
<artifactId>grpc-netty</artifactId>
<version>${grpc.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>io.grpc</groupId>
<artifactId>grpc-protobuf</artifactId>
<version>${grpc.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>io.grpc</groupId>
<artifactId>grpc-core</artifactId>
<version>${grpc.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>io.grpc</groupId>
<artifactId>grpc-stub</artifactId>
<version>${grpc.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>net.devh</groupId>
<artifactId>grpc-server-spring-boot-starter</artifactId>
<version>2.0.1.RELEASE</version>
</dependency>
</dependencies>
<!-- grpc build 插件 -->
<build>
<extensions>
<extension>
<groupId>kr.motd.maven</groupId>
<artifactId>os-maven-plugin</artifactId>
<version>1.4.1.Final</version>
</extension>
</extensions>
<plugins>
<plugin>
<groupId>org.xolstice.maven.plugins</groupId>
<artifactId>protobuf-maven-plugin</artifactId>
<version>0.5.0</version>
<configuration>
<protocArtifact>com.google.protobuf:protoc:3.3.0:exe:${os.detected.classifier}</protocArtifact>
<pluginId>grpc-java</pluginId>
<pluginArtifact>io.grpc:protoc-gen-grpc-java:1.4.0:exe:${os.detected.classifier}</pluginArtifact>
</configuration>
<executions>
<execution>
<goals>
<goal>compile</goal>
<goal>compile-custom</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
理論上,此時執行 mvn -DskipTests=true compile
,即可正常生成gRPC相關的Class類。
target
├── generated-sources
│ ├── annotations
│ └── protobuf
│ ├── grpc-java
│ │ └── cn
│ │ └── lpe234
│ │ └── grpc
│ │ └── grpcdemo
│ │ └── grpc
│ │ └── UserProviderGrpc.java
│ └── java
│ └── cn
│ └── lpe234
│ └── grpc
│ └── grpcdemo
│ └── grpc
│ └── UserProviderOuterClass.java
gPPC服務提供編寫
使用註解(@net.devh.springboot.autoconfigure.grpc.server.GrpcService
)的方式對外提供服務,類似Dubbo服務中的註解方式。
package cn.lpe234.grpc.grpcdemo.grpcprovider;
import cn.lpe234.grpc.grpcdemo.grpc.UserProviderGrpc;
import cn.lpe234.grpc.grpcdemo.grpc.UserProviderOuterClass;
import io.grpc.stub.StreamObserver;
import lombok.extern.slf4j.Slf4j;
import net.devh.springboot.autoconfigure.grpc.server.GrpcService;
/**
* Grpc服務暴露
*
* @author lpe234
* @datetime 2018/11/24 14:36
*/
@Slf4j
@GrpcService(UserProviderGrpc.class)
public class UserProvider extends UserProviderGrpc.UserProviderImplBase {
@Override
public void getByUserId(UserProviderOuterClass.UserIdRequest request, StreamObserver<UserProviderOuterClass.UserVoReplay> responseObserver) {
// super.getByUserId(request, responseObserver);
// 獲取請求數據
long userId = request.getId();
log.debug("grpc request: userId=" + userId);
// 構造返回數據
UserProviderOuterClass.UserVoReplay.Builder userVoReplayBuild = UserProviderOuterClass.UserVoReplay.newBuilder();
userVoReplayBuild.setId(userId);
userVoReplayBuild.setUsername("hello world");
UserProviderOuterClass.UserVoReplay userVoReplay = userVoReplayBuild.build();
// 做出響應
responseObserver.onNext(userVoReplay);
responseObserver.onCompleted();
}
}
gRPC對外服務暴露相關配置
application.xml
文件。需配置綁定的地址和監聽的端口。
# grpc
grpc:
server:
address: 0.0.0.0
port: 10081
運行
如果一切順利的話,啓動Spring Boot項目。可看到控制檯日誌輸出:
2018-11-24 16:51:16.999 INFO 60266 --- [ main] n.d.s.a.g.server.NettyGrpcServerFactory : Registered gRPC service: UserProvider, bean: userProvider, class: cn.lpe234.grpc.grpcdemo.grpcprovider.UserProvider
2018-11-24 16:51:17.124 INFO 60266 --- [ main] n.d.s.a.grpc.server.GrpcServerLifecycle : gRPC Server started, listening on address: 0.0.0.0, port: 10081
2018-11-24 16:51:17.141 INFO 60266 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 10080 (http) with context path ''
2018-11-24 16:51:17.145 INFO 60266 --- [ main] c.l.grpc.grpcdemo.GrpcDemoApplication : Started GrpcDemoApplication in 2.246 seconds (JVM running for 2.721)
可看到:gRPC Server started, listening on address: 0.0.0.0, port: 10081
。說明服務啓動正常~
Golang相關
新建項目 grpc-demo
並 創建子文件夾 grpc-demo/proto
,然後將 最開始的user_provider.proto
拷貝進去(由於proto文件定義了RPC調用的所有細節,即所有服務提供或調用均需要保持版本的相同。拷貝似乎有些不妥~)。
生成Golang gRPC調用相關文件
該步驟,需要一些相關依賴~
protoc --go_out=plugins=grpc:. user_provider.proto
執行成功後,會在該文件夾下生成 user_provider.pb.go
文件。
服務調用
在項目的 src
目錄下,新建main.go
文件。
備註: 地址直接硬編碼畢竟是不好的,暫不考慮服務註冊發現相關內容,知道這塊應該有更好的解決方案即可~
package main
import (
"google.golang.org/grpc"
pb "proto"
"context"
"log"
)
func main() {
// java spring boot 暴露的grpc服務接口
const addr = "127.0.0.1:10081"
// 連接服務
conn, err := grpc.Dial(addr, grpc.WithInsecure())
if err != nil {
log.Panic(err)
}
// 確保連接最終被關閉
defer conn.Close()
// 建立遠程調用客戶端
client := pb.NewUserProviderClient(conn)
reply, err := client.GetByUserId(context.Background(), &pb.UserIdRequest{Id: 1})
if err != nil {
log.Panic(err)
}
// 輸出結果
log.Println("user info:", reply.Id, reply.Username)
}
運行
執行後,可分別在服務調用和提供者日誌中看到如下內容:
# Golang
2018/11/24 17:10:12 user info: 1 hello world
# Spring Boot
2018-11-24 17:10:12.123 DEBUG 60266 --- [ault-executor-1] c.l.g.g.grpcprovider.UserProvider : grpc request: userId=1
完結
至此,已完成了Java提供服務,Golang調用服務。