gRPC是一個高性能、開源、通用的RPC框架,面向移動和HTTP/2設計。gRPC 默認使用 protocol buffers,這是 Google 開源的一套成熟的結構數據序列化機制。java
Protocol Buffers 是一種輕便高效的結構化數據存儲格式,能夠用於結構化數據串行化,或者說序列化。它很適合作數據存儲或 RPC 數據交換格式。可用於通信協議、數據存儲等領域的語言無關、平臺無關、可擴展的序列化結構數據格式。git
本文只是根據gRPC相關資料文檔編寫的Java Spring Boot 與 Golang 語言相關調用的示例。github
使用proto3語法。文件user_provider.proto
。golang
須要使用proto文件,來自動生成不一樣語言的相關接口、類、對象等。spring
// 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; // 用戶名稱 }
使用Maven做爲項目的依賴管理及編譯構建工具。當前使用Maven插件,在編譯時根據proto文件自動生成服務編寫時所需的Class類。tomcat
須要將*.proto
放置在 xxProject/src/main/proto
文件夾下,才能被插件讀取到。也就是proto
文件夾須要跟java
、resources
文件夾並列才行(或許可經過修改配置信息修改proto文件存儲位置,未作深究~)。springboot
項目精簡的pxm.xml配置文件。bash
<!-- 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類。app
target ├── generated-sources │ ├── annotations │ └── protobuf │ ├── grpc-java │ │ └── cn │ │ └── lpe234 │ │ └── grpc │ │ └── grpcdemo │ │ └── grpc │ │ └── UserProviderGrpc.java │ └── java │ └── cn │ └── lpe234 │ └── grpc │ └── grpcdemo │ └── grpc │ └── UserProviderOuterClass.java
使用註解(@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(); } }
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
。說明服務啓動正常~
新建項目 grpc-demo
並 建立子文件夾 grpc-demo/proto
,而後將 最開始的user_provider.proto
拷貝進去(因爲proto文件定義了RPC調用的全部細節,即全部服務提供或調用均須要保持版本的相同。拷貝彷佛有些不妥~)。
該步驟,須要一些相關依賴~
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調用服務。