本文是gRPC的一個簡單例子,以protocol buffers 3作為契約類型,使用gRPC自動生成服務(wù)端和客戶端代碼,實現(xiàn)服務(wù)的遠(yuǎn)程調(diào)用。

-
創(chuàng)建gradle類型工程,
build.gradle文件如下,包含了根據(jù).proto自動生成代碼的插件.apply plugin: 'java' apply plugin: 'com.google.protobuf' buildscript { repositories { maven { url "http://maven.aliyun.com/nexus/content/groups/public/" } } dependencies { classpath 'com.google.protobuf:protobuf-gradle-plugin:0.8.5' } } repositories { maven { url "http://maven.aliyun.com/nexus/content/groups/public/" } mavenLocal() } def grpcVersion = '1.14.0' def nettyTcNativeVersion = '2.0.7.Final' def protobufVersion = '3.5.1' dependencies { compile "com.google.api.grpc:proto-google-common-protos:1.0.0" compile "io.grpc:grpc-alts:${grpcVersion}" compile "io.grpc:grpc-netty:${grpcVersion}" compile "io.grpc:grpc-protobuf:${grpcVersion}" compile "io.grpc:grpc-stub:${grpcVersion}" compileOnly "javax.annotation:javax.annotation-api:1.2" compile "io.netty:netty-tcnative-boringssl-static:${nettyTcNativeVersion}" compile "com.google.protobuf:protobuf-java-util:${protobufVersion}" } protobuf { protoc { artifact = "com.google.protobuf:protoc:3.5.1-1" } plugins { grpc { artifact = 'io.grpc:protoc-gen-grpc-java:1.15.0' } } generateProtoTasks { all()*.plugins { grpc {} } } } -
創(chuàng)建目錄
src/main/proto,并在其中新建契約文件helloworld.proto。這里定義一個請求類型HelloRequest、一個響應(yīng)類型HelloReply,和一個簡單的服務(wù)(service)Greeter。Greeter只提供一個簡單的RPC服務(wù)(simple RPC)sayHellosyntax = "proto3"; package com.mattie.grpc; option java_package = "com.mattie.grpc"; option java_outer_classname = "HelloWorldProtos"; service Greeter { rpc SayHello (HelloRequest) returns (HelloReply) {} } message HelloRequest { string message = 1; } message HelloReply { string message = 1; } -
運(yùn)行命令
gradle clean build,在工程目錄下會生成build文件夾,其中generated目錄下包含由插件io.grpc:protoc-gen-grpc-java所生成的RPC代碼。
生成的代碼目錄 -
生成的
GreeterGrpc.java中包含自定義服務(wù)需要繼承的抽象類GreeterImplBase,以及stub。
GreeterStub(異步返回response)和GreeterBlockingStub(同步等待response)??蛻舳送ㄟ^stub調(diào)用服務(wù)端。
image.png -
定義自己的服務(wù),繼承
GreeterImplBase并重寫契約中定義的服務(wù)sayHello,實現(xiàn)真正的業(yè)務(wù)邏輯。onNext方法用來返回helloReply對象給客戶端,onCompleted方法用來標(biāo)明此次RPC調(diào)用已結(jié)束。public class MyService extends GreeterImplBase { @Override public void sayHello(HelloRequest request, StreamObserver<HelloReply> responseObserver) { HelloReply helloReply = HelloReply.newBuilder().setMessage("hello client.").build(); responseObserver.onNext(helloReply); responseObserver.onCompleted(); } } -
創(chuàng)建好自定義服務(wù)后,就可以新建和啟動一個服務(wù)器,用來接收客戶端的連接。
1. 使用ServerBuilder創(chuàng)建服務(wù)器,forPort方法監(jiān)聽端口
2. 創(chuàng)建MyService的一個實例,并傳遞給ServerBuilder的addService方法
3. 調(diào)用build和start啟動服務(wù)器public class MyServer { public static void main(String[] args) { ServerBuilder<?> serverBuilder = ServerBuilder.forPort(8899); serverBuilder.addService(new MyService()); Server server = serverBuilder.build(); try { server.start(); server.awaitTermination(); } catch (IOException | InterruptedException e) { e.printStackTrace(); } } } -
創(chuàng)建客戶端:
1.創(chuàng)建
gRPC channel,將stub與服務(wù)器連接:這里使用ManagedChannelBuilder來指定主機(jī)和端口將創(chuàng)建的
channel作為參數(shù),創(chuàng)建stub-
使用
stub像調(diào)用本地方法一樣調(diào)用遠(yuǎn)程服務(wù)public class MyClient {
public static void main(String[] args) { //使用usePlaintext,否則使用加密連接 ManagedChannelBuilder<?> channelBuilder = ManagedChannelBuilder.forAddress("localhost", 8899).usePlaintext(); ManagedChannel channel = channelBuilder.build(); GreeterGrpc.GreeterBlockingStub blockingStub = GreeterGrpc.newBlockingStub(channel); HelloWorldProtos.HelloReply helloReply = blockingStub.sayHello(HelloWorldProtos.HelloRequest.newBuilder().setMessage("hello wolrd").build()); System.out.println(helloReply.getMessage()); }}
注:1. clone倉庫后,運(yùn)行
gradle clean build生成build文件夾,并將main目錄設(shè)置為source root。
main目錄設(shè)置為Sources
2..proto文件默認(rèn)需要放在src/main/proto下面,否則無法生成代碼。另外可以自定義存放目錄:自定義.proto文件的存放目錄



