【问题标题】:How to compile protocol buffers schema at runtime?如何在运行时编译协议缓冲区模式?
【发布时间】:2015-02-08 14:56:14
【问题描述】:

我可以在运行时使用 FileDescriptorProto 动态创建架构 (Descriptors.Descriptor),还可以使用 DynamicMessage 序列化和反序列化消息。

但是DynamicMessage 的性能不够好,因为它构造消息的方式。我想知道是否可以在运行时编译模式并在反序列化消息时使用它以获得更好的性能。

如果协议缓冲区没有提供在运行时编译模式的方法,那么如果可以将 Descriptors.Descriptor 转换为临时 .proto 文件,那么我可以尝试通过调用我的 protoc 命令来生成类程序并使用 Class.forName API 将它们加载到程序中。

【问题讨论】:

  • 你能分享一个例子吗?或工作代码,您可以在运行时使用 FileDescriptor 动态创建模式。我面临着和你类似的情况。我们有一个代表整个消息类的字符串(通常包含在 .proto 文件中),我想生成一个类,我可以使用它来读取使用上述消息类序列化的消息。
  • 我也遇到了类似的问题,想知道你最终得到了什么解决方案?

标签: java protocol-buffers java-compiler-api


【解决方案1】:

Protocol Buffers 不包括任何类型的内置“JIT”编译。

如果您想生成代码并在运行时使用 javac 编译它,并且您从 FileDescriptorProto 开始,那么您可能想要做的是直接调用 Java 代码生成器(不转换 proto 定义成文本)。

您可以通过编写一个创建google::protobuf::compiler::java::JavaGenerator 并将其传递给google::protobuf::compiler::PluginMain() 的小C++ 程序来完成此操作。您现在有一个程序从标准输入读取CodeGeneratorRequest 并将CodeGeneratorResponse 写入标准输出。因此,您可以执行此程序以直接从FileDescirptorProtos 生成 Java 代码。将此代码传递给 Java 编译器取决于您。这应该比尝试生成要传递给protoc 的文本更容易和更清晰。

【讨论】:

  • 不幸的是,我没有足够的 C++ 经验,所以我认为我很难维护该插件并将其分发到集群中的节点中。 javac 编译器实际上并不即时编译代码,因此即使我直接从标准输入读取源代码,我仍然需要将其写入文件才能使用 javac。我想也许 protobuf 可以提供一种将 FileDescriptorProto 序列化回 .proto 定义的方法,因为它已经使用该定义来构造 FileDescriptorProto,但如果不是,那么我会按照你的方式进行。
  • FWIW,这里必要的 C++ 代码对于整个程序来说大约有四行——它只是创建了一个 JavaGenerator 并将其传递给 PluginMain。 ;;我对您对javac 的反对感到有些困惑——即使您将FileDescriptorProto 转换回文本,然后将其输入protoc,输出仍然是Java 代码,所以您仍然需要javac 或类似的东西它。
  • 我认为您建议我编写一个小插件的原因是可移植性问题,因为该程序允许我直接向程序写入/读取数据而无需使用文件系统。但是,即使我从该程序中读取了 java 源代码,我仍然需要将其写入文件系统以运行 javac 编译器,因此该插件对我的唯一好处是将 FileDescriptorProto 实例转换为 protoc 定义不再需要。 protoc 也很容易通过 linux 中的包管理器安装,但如果我编写插件,我还必须自己将其分发到节点。
  • 不,我建议使用插件方法的原因是因为它比尝试将 FileDescriptorProto 转换回 .proto 文件更容易和更干净。 :) 我怀疑使用这种方法你会遇到更多麻烦(编写更多代码,有更多错误)。
  • 哦,我知道了。感谢您的建议,我会尝试一下。 :)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-05-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多