mtS*_*Chi 9 java protocol-buffers grpc grpc-java
使用 gRPC 时,我们需要通过协议缓冲区编译器 (protoc) 或使用 Gradle 或 Maven protoc 构建插件从 .proto 服务定义生成 gRPC 客户端和服务器接口。
Flow now: protobuf file -> java code -> gRPC client.
Run Code Online (Sandbox Code Playgroud)
那么,有没有办法可以跳过这一步呢?
如何创建一个通用的 gRPC 客户端,可以直接从 protobuf 文件调用服务器,而无需编译成 java 代码?或者,有没有办法在运行时生成代码?
Flow expect: protobuf file -> gRPC client.
Run Code Online (Sandbox Code Playgroud)
我想构建一个通用的 gRPC 客户端系统,输入是 protobuf 文件以及方法、包、消息请求的描述......而不必为每个 protobuf 再次编译。
非常感谢。
Protobuf 系统确实需要 protoc 才能运行。但是,可以跳过生成的代码。您可以传递将文件解析为描述符文件的内容,而不是将类似 和 的--java_out
内容传递给协议。描述符文件是原始编码的. 这与反射服务使用的基本格式相同。--grpc_java_out
--descriptor_set_out=FILE
.proto
FileDescriptorSet
一旦有了描述符,您就可以一次加载一个 FileDescriptor并创建一个 DynamicMessage。
然后对于 gRPC 部分,您需要创建一个 gRPC MethodDescriptor。
static MethodDescriptor from(
Descriptors.MethodDescriptor methodDesc
) {
return MethodDescriptor.<DynamicMessage, DynamicMessage>newBuilder()
// UNKNOWN is fine, but the "correct" value can be computed from
// methodDesc.toProto().getClientStreaming()/getServerStreaming()
.setType(getMethodTypeFromDesc(methodDesc))
.setFullMethodName(MethodDescriptor.generateFullMethodName(
serviceDesc.getFullName(), methodDesc.getName()))
.setRequestMarshaller(ProtoUtils.marshaller(
DynamicMessage.getDefaultInstance(methodDesc.getInputType())))
.setResponseMarshaller(ProtoUtils.marshaller(
DynamicMessage.getDefaultInstance(methodDesc.getOutputType())))
.build();
static MethodDescriptor.MethodType getMethodTypeFromDesc(
Descriptors.MethodDescriptor methodDesc
) {
if (!methodDesc.isServerStreaming()
&& !methodDesc.isClientStreaming()) {
return MethodDescriptor.MethodType.UNARY;
} else if (methodDesc.isServerStreaming()
&& !methodDesc.isClientStreaming()) {
return MethodDescriptor.MethodType.SERVER_STREAMING;
} else if (!methodDesc.isServerStreaming()) {
return MethodDescriptor.MethodType.CLIENT_STREAMING);
} else {
return MethodDescriptor.MethodType.BIDI_STREAMING);
}
}
Run Code Online (Sandbox Code Playgroud)
到那时,您就拥有了所需的一切,并且可以Channel.newCall(method, CallOptions.DEFAULT)
在 gRPC 中调用。您还可以自由地使用ClientCalls
与存根 API 更相似的东西。
因此动态调用绝对是可能的,并且用于grpcurl之类的事情。但这也并不容易,因此通常只在必要时才进行。
从技术上讲,两者都是可能的。
代码生成器只是生成一些类;主要是protobuf消息、grpc方法描述符和存根。您可以实现它或签入生成的代码以绕过代码生成。我不确定这样做有什么好处。另外,如果原型改变了,也会很烦人。
只要您签入一些接口/抽象类来表示那些生成的存根/方法描述符和 protobuf 消息,也可以使用字节代码生成器动态地执行此操作。您必须确保这些非动态代码与原型定义同步(最有可能的是运行时检查/异常)。
归档时间: |
|
查看次数: |
11228 次 |
最近记录: |