如何直接从 protobuf 创建 GRPC 服务器而不将其编译成 java 代码

How to create GRPC server directly from protobuf without compiling it into java code

有必要实现一个通用的 GRPC 服务器作为存根。

没有找到任何类似的服务器,只有客户端。

非常感谢!

可能有一些方法可以从包含 services 的 protobuf 动态构建 gRPC 服务器,但这不是很有用。事实上,Rust crates、Node.js 和其他实现确实动态生成代码,而无需直接使用 protoc 的额外手动步骤。

正如评论者所建议的那样,proto 文件只定义了服务方法名称及其输入和输出消息,因此,假设的服务器除了接收消息之外不会对消息做任何事情并且可能发送空回复。

因为原型是强类型的,所以以这种方式存根服务器也没有任何好处,因为您的(例如 Java)客户端将能够创建类型良好的消息(没有服务器)。

您的用例是什么?这可能有助于建议其他答案。

我相信您想使用生成的服务器进行测试?如果是这样,有一种做法叫做service virtualization or API simulation - a subset of the test double family。它允许您“模拟”或“存根”真实系统,以便测试被测系统。其中一些工具允许导入模式文件以生成存根(即 Swagger/OpenAPI/Proto/WSDL/...)。

Wikipedia contains a list of those tools. Looking at that list today one of those tools that support gRPC is called Traffic Parrot which allows you to create gRPC mocks based on your Proto files. There are also open-source tools like GripMock 但它不会根据 Proto 文件生成存根,您必须手动创建它们。

请记住,生成的 stub/mock/simulator 只是一个 test double,它不会复制 Proto 文件对应的系统的完整行为。导入 Proto 文件并生成服务器测试替身的工具只能知道消息的语法,而不是语义,也不知道真实系统的行为。

如果您还想部分复制消息的语义,请考虑 recording of gRPC messages to create service stubs,这样您也可以看到示例数据。

如果您不想处理 protobuf 消息,那么您需要创建一个 Marshaller that serializes to/from byte[], a MethodDescriptor for each method you want to support, and a ServerCallHandler for your application logic. You might find a grpc proxy mockup helpful. Those can be combined together to pass to serverBuilder.addService(ServerServiceDefinition). You can also use ServerCalls 来帮助制作一个 ServerCallHandler.

class ByteMarshaller implements MethodDescriptor.Marshaller<byte[]> {
  @Override public byte[] parse(InputStream stream) {
    try {
      return ByteStreams.toByteArray(stream);
    } catch (IOException ex) {
      throw new RuntimeException();
    }
  }

  @Override public InputStream stream(byte[] value) {
    return new ByteArrayInputStream(value);
  }
};
class YourHandler extends ServerCallHandler<byte[],byte[]> {...}

MethodDescriptor<> desc = MethodDescriptor.<byte[], byte[]>newBuilder()
    // UNKNOWN is fine, but specify the type if you know it
    .setType(MethodDescriptor.MethodType.UNKNOWN)
    .setFullMethodName("package.YourService/Method"))
    .setRequestMarshaller(new ByteMarshaller())
    .setResponseMarshaller(new ByteMarshaller())
    .build();
serverBuilder.addService(
    ServiceDescriptor.newBuilder("package.YourService")
      .addMethod(ServerMethodDefinition.create(desc, new YourHandler()))
      .build());

如果你想解析 protobuf,那么你可以使用 DynamicMessage 和 gRPC 的 Protobuf Marshaller。 A similar client-side question 解释了这个过程。