java - 运行时生成的 Protocol Buffer 对象

标签 java protocol-buffers

我的一位同事提出了在运行时生成 Protocol Buffer 类的想法。意义:

  • C++ 服务器应用程序和 Java 客户端应用程序通过 Protocol Buffer 消息通过 TCP/IP 进行通信。
  • C++ 应用程序在不同版本中可能有不同的模式,这不一定向后兼容
  • 有与此服务器通信的 Java 应用程序应该支持所有可能的服务器版本。

  • 这个想法是服务器发送 Protocol Buffer 的定义作为初始握手的一部分,Java 应用程序在运行时生成类并使用它与服务器进行通信。

    我想知道这是否是至关重要的想法,以及是否可能有一些适用于此类用例的实用程序。

    谢谢

    最佳答案

    您描述的内容实际上已经被 C++ 和 Java 中的 Protocol Buffer 实现支持。您所要做的就是发送一个 FileDescriptorSet (在 google/protobuf/descriptor.proto 中定义)包含 FileDescriptorProto s 代表每个相关 .proto文件,然后使用 DynamicMessage在接收端解释消息。

    获取 FileDescriptorProto在 C++ 中,给定消息类型 Foo在该文件中定义的,请执行以下操作:

    google::protobuf::FileDescriptorProto file;
    Foo::descriptor().file()->CopyTo(&file);
    

    把所有的FileDescriptorProto s 定义您需要的类型,以及它们导入的所有文件,放入 FileDescriptorSet原型(prototype)。请注意,您可以使用 google::protobuf::FileDescriptor (由 Foo::descriptor().file() 返回的东西)迭代依赖项而不是显式命名每个依赖项。

    现在,发送 FileDescriptorSet给客户。

    在客户端,使用 FileDescriptor.buildFrom() 转换每个 FileDescriptorProto直播 Descriptors.FileDescriptor .您必须确保在依赖项之前构建依赖项,因为您必须将已经构建的依赖项提供给 buildFrom() 在构建依赖项时。

    从那里,您可以使用 FileDescriptor findMessageTypeByName() 找到 Descriptor 对于您关心的特定消息类型。

    最后可以拨打 DynamicMessage.newBuilder(descriptor) 为相关类型构造一个新的构建器实例。 DynamicMessage.Builder 实现 Message.Builder 接口(interface),其中包含 getField() 等字段和 setField() 动态操作消息的字段(通过指定相应的 FieldDescriptor s)。

    同样,您可以拨打 DynamicMessage.parseFrom(descriptor,input) 解析从服务器收到的消息。

    请注意 DynamicMessage 的一个缺点就是比较慢。本质上,它就像一种解释型语言。生成的代码更快,因为编译器可以针对特定类型进行优化,而 DynamicMessage 必须能够处理任何类型。

    然而,真的没有办法解决这个问题。即使您在运行时运行代码生成器并编译类,实际使用新类的代码仍然是您之前编写的代码,在您知道将使用什么类型之前。因此,它仍然必须使用反射或类似反射的接口(interface)来访问消息,这比为特定类型手写代码要慢。

    但这是个好主意吗?

    嗯,这取决于。客户端实际上将如何处理它从服务器接收到的这个模式?通过网络传输模式并不会神奇地使客户端与该版本的协议(protocol)兼容——客户端仍然必须了解协议(protocol)的含义。如果协议(protocol)以向后不兼容的方式更改,这几乎肯定意味着协议(protocol)的含义已经更改,并且客户端代码必须更新,模式传输与否。您可以期望客户端在没有更新的情况下继续工作的唯一时间是客户端只执行仅依赖于消息内容而不是消息含义的通用操作——例如,客户端可以将消息转换为 JSON无需知道这意味着什么。但这是相对不寻常的,尤其是在应用程序的客户端。这正是 Protobufs 在默认情况下不发送任何类型信息的原因——因为它通常是无用的,因为如果接收者不知道其含义,则模式是无关紧要的。

    如果问题是服务器向客户端发送的消息根本不打算被解释,而是稍后发送回服务器,那么客户端根本不需要模式。只需将消息发送为 bytes不要费心解析它。请注意,一个 bytes包含 Foo 类型的编码消息的字段在线路上看起来与类型实际声明为 Foo 的字段完全相同。 .您实际上可以针对 .proto 的略有不同版本编译客户端和服务器。文件,其中客户端将特定字段视为 bytes而服务器将其视为子消息,以避免客户端需要知道该子消息的定义。
    ``

    关于java - 运行时生成的 Protocol Buffer 对象,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18836727/

    相关文章:

    java - Hibernate HQL否定 'is'语句的正确语法是什么

    java - 使用 GBC/GBL 在 JPanel 上定位 JButton

    gradle - Android Studio 2.2's incremental compiler can' t 查看生成的 protobuf

    java - grpc protobuf java 中的 NoSuchMethodException 和 NoClassDefFoundError

    java - 无法获取文本文件的 URI

    java - 根据内容的大小设置框架最小尺寸

    java - 布局 xml 中自定义 View 的空指针异常

    c# - 如何使用protobuf.net序列化dictionary<int, List<CustomeObject>>?

    android - 带有 Android Studio 的 Protobuf

    enums - 使用 protobuf 枚举值作为字段编号