Protobuf 系统确实需要 protoc 才能运行。但是,可以跳过生成的代码。而不是传递类似的东西--java_out
and --grpc_java_out
到协议你可以通过--descriptor_set_out=FILE
这将解析.proto
文件到一个描述符文件。描述符文件是一个原始编码FileDescriptorSet https://github.com/protocolbuffers/protobuf/blob/3be9322e28dfcacdb669f646f76fe833fa274107/src/google/protobuf/descriptor.proto#L57。这与反射服务使用的基本格式相同。
一旦有了描述符,您就可以一次加载一个 FileDescriptor https://developers.google.com/protocol-buffers/docs/reference/java/com/google/protobuf/Descriptors.FileDescriptor.html#buildFrom-com.google.protobuf.DescriptorProtos.FileDescriptorProto-com.google.protobuf.Descriptors.FileDescriptor:A- and 创建动态消息 https://developers.google.com/protocol-buffers/docs/reference/java/com/google/protobuf/DynamicMessage.html#getDefaultInstance-com.google.protobuf.Descriptors.Descriptor-.
然后对于 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);
}
}
那时你已经拥有了你需要的一切并且可以打电话Channel.newCall(method, CallOptions.DEFAULT) https://grpc.github.io/grpc-java/javadoc/io/grpc/Channel.html#newCall-io.grpc.MethodDescriptor-io.grpc.CallOptions-在 gRPC 中。您也可以免费使用ClientCalls https://grpc.github.io/grpc-java/javadoc/io/grpc/stub/ClientCalls.html使用与存根 API 更相似的东西。
所以动态调用绝对是可能的,并且用于诸如grpcurl https://github.com/fullstorydev/grpcurl。但这也并不容易,因此通常只在必要时才进行。