代码生成参考

代码生成参考

对于在 .proto 文件中定义的每个服务,Java 代码生成会生成一个 Java 类。类名是服务的名称,后缀为 Grpc。生成的代码的包在 .proto 文件中使用 java_package 选项指定。

例如,如果 ServiceName 在包含以下内容的 .proto 文件中定义

package grpcexample;

option java_package = "io.grpc.examples";

那么生成的类将是 io.grpc.examples.ServiceNameGrpc

如果未指定 java_package,则生成的类将使用 .proto 文件中指定的 package。应避免这种情况,因为 proto 包通常不以反向域名开头。

服务存根

生成的 Java 代码包含一个后缀为 ImplBase 的内部抽象类,例如 ServiceNameImplBase。此类为服务定义中的每个方法定义一个 Java 方法。服务实现者可以扩展此类并实现这些方法的功能。如果未被覆盖,这些方法将向客户端返回一个错误,说明该方法未实现。

ServiceNameImplBase 中存根方法的签名取决于它处理的 RPC 的类型。gRPC 服务方法有四种类型:一元、服务器流式、客户端流式和双向流式。

一元

一元 RPC 方法 unaryExample 的服务存根签名

public void unaryExample(
    RequestType request,
    StreamObserver<ResponseType> responseObserver)

服务器流式

服务器流式 RPC 方法 serverStreamingExample 的服务存根签名

public void serverStreamingExample(
    RequestType request,
    StreamObserver<ResponseType> responseObserver)

请注意,一元和服务器流式 RPC 的签名是相同的。从客户端接收单个 RequestType,服务实现通过调用 responseObserver.onNext(ResponseType response) 来发送其响应。

客户端流式

客户端流式 RPC 方法 clientStreamingExample 的服务存根签名

public StreamObserver<RequestType> clientStreamingExample(
    StreamObserver<ResponseType> responseObserver)

双向流式

双向流式 RPC 方法 bidirectionalStreamingExample 的服务存根签名

public StreamObserver<RequestType> bidirectionalStreamingExample(
    StreamObserver<ResponseType> responseObserver)

客户端和双向流式 RPC 的签名是相同的。由于客户端可以向服务发送多条消息,因此服务实现负责返回一个 StreamObserver<RequestType> 实例。每当从客户端收到其他消息时,都会调用此 StreamObserver

客户端存根

生成的类还包含供 gRPC 客户端使用的存根,以调用服务定义的方法。每个存根都封装了一个 Channel,该通道由生成代码的用户提供。存根使用此通道将 RPC 发送到服务。

gRPC Java 生成三种类型的存根的代码:异步、阻塞和 future。每种类型的存根在生成的代码中都有一个对应的类,例如 ServiceNameStubServiceNameBlockingStubServiceNameFutureStub

异步存根

通过异步存根进行的 RPC 完全通过 StreamObserver 上的回调来操作。

异步存根包含服务定义中每个方法的一个 Java 方法。

通过 ServiceNameGrpc.newStub(Channel channel) 静态方法实例化新的异步存根。

一元

一元 RPC 方法 unaryExample 的异步存根签名

public void unaryExample(
    RequestType request,
    StreamObserver<ResponseType> responseObserver)

服务器流式

服务器流式 RPC 方法 serverStreamingExample 的异步存根签名

public void serverStreamingExample(
    RequestType request,
    StreamObserver<ResponseType> responseObserver)

客户端流式

客户端流式 RPC 方法 clientStreamingExample 的异步存根签名

public StreamObserver<RequestType> clientStreamingExample(
    StreamObserver<ResponseType> responseObserver)

双向流式

双向流式 RPC 方法 bidirectionalStreamingExample 的异步存根签名

public StreamObserver<RequestType> bidirectionalStreamingExample(
    StreamObserver<ResponseType> responseObserver)

阻塞存根

顾名思义,通过阻塞存根进行的 RPC 会阻塞,直到服务的响应可用为止。

阻塞存根包含服务定义中每个一元和服务器流式方法的一个 Java 方法。阻塞存根不支持客户端流式或双向流式 RPC。

通过 ServiceNameGrpc.newBlockingStub(Channel channel) 静态方法实例化新的阻塞存根。

一元

一元 RPC 方法 unaryExample 的阻塞存根签名

public ResponseType unaryExample(RequestType request)

服务器流式

服务器流式 RPC 方法 serverStreamingExample 的阻塞存根签名

public Iterator<ResponseType> serverStreamingExample(RequestType request)

Future 存根

通过 future 存根进行的 RPC 将异步存根的返回值包装在 GrpcFuture<ResponseType> 中,该类实现了 com.google.common.util.concurrent.ListenableFuture 接口。

Future 存根包含服务定义中每个一元方法的一个 Java 方法。Future 存根不支持流式调用。

通过 ServiceNameGrpc.newFutureStub(Channel channel) 静态方法实例化新的 future 存根。

一元

一元 RPC 方法 unaryExample 的 future 存根签名

public ListenableFuture<ResponseType> unaryExample(RequestType request)

代码生成

通常,构建系统会处理 gRPC 生成的代码的创建。

对于基于 protobuf 的代码生成,您可以将 .proto 文件与适当的插件一起放在 src/main/protosrc/test/proto 目录中。

一个典型的用于生成 gRPC 和 Protocol Buffers 代码的 protobuf-maven-plugin 配置如下所示

<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>

Eclipse 和 NetBeans 用户还应查看 os-maven-pluginIDE 文档

一个典型的 protobuf-gradle-plugin 配置如下所示

apply plugin: 'java'
apply plugin: 'com.google.protobuf'

buildscript {
  repositories {
    mavenCentral()
  }
  dependencies {
    // ASSUMES GRADLE 2.12 OR HIGHER. Use plugin version 0.7.5 with earlier
    // gradle versions
    classpath 'com.google.protobuf:protobuf-gradle-plugin:0.8.0'
  }
}

protobuf {
  protoc {
    artifact = "com.google.protobuf:protoc:3.2.0"
  }
  plugins {
    grpc {
      artifact = 'io.grpc:protoc-gen-grpc-java:1.4.0'
    }
  }
  generateProtoTasks {
    all()*.plugins {
      grpc {}
    }
  }
}

Bazel 开发人员可以使用 java_grpc_library 规则,通常如下所示

load("@grpc_java//:java_grpc_library.bzl", "java_grpc_library")

proto_library(
    name = "helloworld_proto",
    srcs = ["src/main/proto/helloworld.proto"],
)

java_proto_library(
    name = "helloworld_java_proto",
    deps = [":helloworld_proto"],
)

java_grpc_library(
    name = "helloworld_java_grpc",
    srcs = [":helloworld_proto"],
    deps = [":helloworld_java_proto"],
)

Android 开发人员,请参阅 生成客户端代码 以供参考。

如果您希望直接调用 gRPC Java 的 protobuf 插件,命令行语法如下所示

protoc --plugin=protoc-gen-grpc-java \
    --grpc-java_out="$OUTPUT_FILE" --proto_path="$DIR_OF_PROTO_FILE" "$PROTO_FILE"