本文是gRPC的一个简单例子,以protocol buffers 3作为契约类型,使用gRPC自动生成服务端和客户端代码,实现服务的远程调用。

-
创建gradle类型工程,
build.gradle文件如下,包含了根据.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 {} } } } -
创建目录
src/main/proto,并在其中新建契约文件helloworld.proto。这里定义一个请求类型HelloRequest、一个响应类型HelloReply,和一个简单的服务(service)Greeter。Greeter只提供一个简单的RPC服务(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; } -
运行命令
gradle clean build,在工程目录下会生成build文件夹,其中generated目录下包含由插件io.grpc:protoc-gen-grpc-java所生成的RPC代码。
生成的代码目录 -
生成的
GreeterGrpc.java中包含自定义服务需要继承的抽象类GreeterImplBase,以及stub。
GreeterStub(异步返回response)和GreeterBlockingStub(同步等待response)。客户端通过stub调用服务端。
image.png -
定义自己的服务,继承
GreeterImplBase并重写契约中定义的服务sayHello,实现真正的业务逻辑。onNext方法用来返回helloReply对象给客户端,onCompleted方法用来标明此次RPC调用已结束。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(); } } -
创建好自定义服务后,就可以新建和启动一个服务器,用来接收客户端的连接。
1. 使用ServerBuilder创建服务器,forPort方法监听端口
2. 创建MyService的一个实例,并传递给ServerBuilder的addService方法
3. 调用build和start启动服务器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(); } } } -
创建客户端:
1.创建
gRPC channel,将stub与服务器连接:这里使用ManagedChannelBuilder来指定主机和端口将创建的
channel作为参数,创建stub-
使用
stub像调用本地方法一样调用远程服务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仓库后,运行
gradle clean build生成build文件夹,并将main目录设置为source root。
main目录设置为Sources
2..proto文件默认需要放在src/main/proto下面,否则无法生成代码。另外可以自定义存放目录:自定义.proto文件的存放目录




