5.2. 使用 ProtoStream 的 Marshalling User Types


用户类型为 Data Grid 不支持的 Java 对象。要进行 marshall 用户类型,您可以实施 SerializationContextInitializer 接口来描述 Java 对象,以便 ProtoStream 库可以对其进行编码,而 Data Grid 可以传输和存储它们。

5.2.1. 生成 Serialization Context Initializers

ProtoStream SerializationContext 包含自定义 Java 对象的 Protobuf 类型定义,从 Protobuf 模式加载,以及这些对象的附带的 marshallers。

Data Grid 提供了一个 protostream-processor 工件,可在编译时处理您的类中的 Java 注解。处理器生成 Protobuf 模式、marshallers 和 SerializationContext 接口的具体实施,您可以使用它来初始化 ProtoStream SerializationContext

注意

默认情况下,实施名称是注解的类名称,带有 "Impl" 后缀。

流程

  1. protostream-processor 依赖项添加到 pom.xml 中。

    <dependencyManagement>
      <dependencies>
        <dependency>
          <groupId>org.infinispan</groupId>
          <artifactId>infinispan-bom</artifactId>
          <version>${version.infinispan}</version>
          <type>pom</type>
        </dependency>
      </dependencies>
    </dependencyManagement>
    
    <dependencies>
      <dependency>
        <groupId>org.infinispan.protostream</groupId>
        <artifactId>protostream-processor</artifactId>
        <!--
          This dependency should be declared in the "provided" scope or made "optional"
          because it is a compile-only dependency and is not required at runtime.
          Transitive propagation of this dependency should be also be avoided.
        -->
        <scope>provided</scope>
      </dependency>
    </dependencies>
    Copy to Clipboard Toggle word wrap
  2. 使用 @ProtoField@ProtoFactory 注解您要 marshall 的 Java 对象。

    Author.java

    import org.infinispan.protostream.annotations.ProtoFactory;
    import org.infinispan.protostream.annotations.ProtoField;
    
    public class Author {
       @ProtoField(number = 1)
       final String name;
    
       @ProtoField(number = 2)
       final String surname;
    
       @ProtoFactory
       Author(String name, String surname) {
          this.name = name;
          this.surname = surname;
       }
       // public Getter methods omitted for brevity
    }
    Copy to Clipboard Toggle word wrap

    Book.java

    import org.infinispan.protostream.annotations.ProtoFactory;
    import org.infinispan.protostream.annotations.ProtoField;
    ...
    
    public class Book {
       @ProtoField(number = 1)
       final String title;
    
       @ProtoField(number = 2)
       final String description;
    
       @ProtoField(number = 3, defaultValue = "0")
       final int publicationYear;
    
       @ProtoField(number = 4, collectionImplementation = ArrayList.class)
       final List<Author> authors;
    
       @ProtoFactory
       Book(String title, String description, int publicationYear, List<Author> authors) {
          this.title = title;
          this.description = description;
          this.publicationYear = publicationYear;
          this.authors = authors;
       }
       // public Getter methods omitted for brevity
    }
    Copy to Clipboard Toggle word wrap

  3. 定义扩展 SerializationContextInitializer 的接口,并使用 @AutoProtoSchemaBuilder 标注。

    @AutoProtoSchemaBuilder(
          includeClasses = {
                Book.class,
                Author.class,
          },
          schemaFileName = "library.proto", 
    1
    
          schemaFilePath = "proto/", 
    2
    
          schemaPackageName = "book_sample")
    interface LibraryInitializer extends SerializationContextInitializer {
    }
    Copy to Clipboard Toggle word wrap
    1
    将生成的 .proto 模式文件命名为 .proto。
    2
    在生成 schema 文件的 target/classes 下设置路径。

后续步骤

SerializationContextInitializer 实现添加到 Data Grid 配置中以注册它。

请参阅 Registering Serialization Context Initializers

5.2.2. 手动实施 Serialization Context Initializers

在某些情况下,您可能需要手动定义 Protobuf 模式,并实现 ProtoStream marshallers。例如,如果无法修改 Java 对象类来添加注解。

流程

  1. 创建一个 Protobuf 模式 .proto 文件,为 marshall 提供 Java 对象的结构化表示。

    package book_sample;
    
    message Book {
        optional string title = 1;
        optional string description = 2;
        optional int32 publicationYear = 3; // no native Date type available in Protobuf
    
        repeated Author authors = 4;
    }
    
    message Author {
        optional string name = 1;
        optional string surname = 2;
    }
    Copy to Clipboard Toggle word wrap

    前面的 .library.proto 文件定义了名为 Book 的实体(Protobuf 消息类型),该实体包含在 book_sample 软件包中。本书 声明了原语类型的多个字段以及名为 author 的数组(Protobuf 可重复字段),即 Author 消息类型。

    • 您可以嵌套消息,但生成的结构严格是一个树,而不是图形。
    • 类型继承是不可能的。
    • 不支持集合,但您可以使用重复字段模拟数组。
  2. 使用 org.infinispan.protostream.MessageMarshaller 接口为您的类实施 marshallers。

    注意

    MessageMarshaller 接口现已弃用。

    下一个版本的 Data Grid 提供了一种替代的实现,可让您创建一个 adaptor 类,该类将 @ProtoAdaptor 注释用于任何外部的第三方 Java 对象类。

    BookMarshaller.java

    import org.infinispan.protostream.MessageMarshaller;
    
    public class BookMarshaller implements MessageMarshaller<Book> {
    
       @Override
       public String getTypeName() {
          return "book_sample.Book";
       }
    
       @Override
       public Class<? extends Book> getJavaClass() {
          return Book.class;
       }
    
       @Override
       public void writeTo(MessageMarshaller.ProtoStreamWriter writer, Book book) throws IOException {
          writer.writeString("title", book.getTitle());
          writer.writeString("description", book.getDescription());
          writer.writeInt("publicationYear", book.getPublicationYear());
          writer.writeCollection("authors", book.getAuthors(), Author.class);
       }
    
       @Override
       public Book readFrom(MessageMarshaller.ProtoStreamReader reader) throws IOException {
          String title = reader.readString("title");
          String description = reader.readString("description");
          int publicationYear = reader.readInt("publicationYear");
          List<Author> authors = reader.readCollection("authors", new ArrayList<>(), Author.class);
          return new Book(title, description, publicationYear, authors);
       }
    }
    Copy to Clipboard Toggle word wrap

    AuthorMarshaller.java

    import org.infinispan.protostream.MessageMarshaller;
    
    public class AuthorMarshaller implements MessageMarshaller<Author> {
    
       @Override
       public String getTypeName() {
          return "book_sample.Author";
       }
    
       @Override
       public Class<? extends Author> getJavaClass() {
          return Author.class;
       }
    
       @Override
       public void writeTo(MessageMarshaller.ProtoStreamWriter writer, Author author) throws IOException {
          writer.writeString("name", author.getName());
          writer.writeString("surname", author.getSurname());
       }
    
       @Override
       public Author readFrom(MessageMarshaller.ProtoStreamReader reader) throws IOException {
          String name = reader.readString("name");
          String surname = reader.readString("surname");
          return new Author(name, surname);
       }
    }
    Copy to Clipboard Toggle word wrap

  3. 创建一个 SerializationContextInitializer 实现,它使用 SerializationContext 注册 .proto 模式和 ProtoStream marshaller 实现。

    ManualSerializationContextInitializer.java

    import org.infinispan.protostream.FileDescriptorSource;
    import org.infinispan.protostream.SerializationContext;
    import org.infinispan.protostream.SerializationContextInitializer;
    ...
    
    public class ManualSerializationContextInitializer implements SerializationContextInitializer {
       @Override
       public String getProtoFileName() {
          return "library.proto";
       }
    
       @Override
       public String getProtoFile() throws UncheckedIOException {
          // Assumes that the file is located in a Jar's resources, we must provide the path to the library.proto file
          return FileDescriptorSource.getResourceAsString(getClass(), "/" + getProtoFileName());
       }
    
       @Override
       public void registerSchema(SerializationContext serCtx) {
          serCtx.registerProtoFiles(FileDescriptorSource.fromString(getProtoFileName(), getProtoFile()));
       }
    
       @Override
       public void registerMarshallers(SerializationContext serCtx) {
          serCtx.registerMarshaller(new AuthorMarshaller());
          serCtx.registerMarshaller(new BookMarshaller());
       }
    }
    Copy to Clipboard Toggle word wrap

后续步骤

SerializationContextInitializer 实现添加到 Data Grid 配置中以注册它。

请参阅 Registering Serialization Context Initializers

5.2.3. 注册 Serialization Context Initializers

在 Data Grid 配置中声明 SerializationContextInitializer 实现来注册它们。

流程

  • 手动以编程方式或声明性注册 SerializationContextInitializer 实现,如下例所示:

编程配置

GlobalConfigurationBuilder builder = new GlobalConfigurationBuilder();
builder.serialization()
       .addContextInitializers(new LibraryInitializerImpl(), new SCIImpl());
Copy to Clipboard Toggle word wrap

声明性配置

<serialization>
    <context-initializer class="org.infinispan.example.LibraryInitializerImpl"/>
    <context-initializer class="org.infinispan.example.another.SCIImpl"/>
</serialization>
Copy to Clipboard Toggle word wrap

返回顶部
Red Hat logoGithubredditYoutubeTwitter

学习

尝试、购买和销售

社区

关于红帽文档

通过我们的产品和服务,以及可以信赖的内容,帮助红帽用户创新并实现他们的目标。 了解我们当前的更新.

让开源更具包容性

红帽致力于替换我们的代码、文档和 Web 属性中存在问题的语言。欲了解更多详情,请参阅红帽博客.

關於紅帽

我们提供强化的解决方案,使企业能够更轻松地跨平台和环境(从核心数据中心到网络边缘)工作。

Theme

© 2025 Red Hat