2.2. 创建序列化上下文初始化器


序列化上下文初始化程序可让您在 Data Grid 中注册以下内容:

  • 描述用户类型的 protobuf 模式。
  • 提供序列化和反序列化功能的 Marshallers。

在高级别中,您应该执行以下操作来创建序列化上下文初始化器:

  1. 在 Java 类中添加 ProtoStream 注解。
  2. 使用 Data Grid 提供的 ProtoStream 处理器来编译您的 SerializationContextInitializer 实现。
注意

org.infinispan.protostream.MessageMarshaller 接口已弃用,计划在以后的 ProtoStream 版本中删除。您应该忽略任何显示如何使用 MessageMarshaller 的代码示例或文档,直到完全删除为止。

2.2.1. 添加 ProtoStream 处理器

Data Grid 提供了一个 ProtoStream 处理器工件,它在编译时在编译时处理类中的 Java 注解,以生成 Protobuf 模式、marshallers 以及 SerializationContextInitializer 接口的聚合实现。

流程

  • protostream-processor 依赖项添加到带有 提供的 范围的 pom.xml 中。

    注意

    这个依赖项只在编译时需要,因此您应该使用 所提供的 范围或将其标记为可选。您还应确保 protostream-processor 没有作为传输的依赖关系传播。

    <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>
        <scope>provided</scope>
      </dependency>
    </dependencies>

2.2.2. 在 Java 类中添加 ProtoStream 注解

通过在 Java 类及其成员中添加注解来声明 ProtoStream 元数据。然后,Data Grid 使用 ProtoStream 处理器从这些注解生成 Protobuf 模式和相关 marshallers。

流程

  1. 使用 @ProtoField 注解您要 marshall 的 Java 字段,可以直接在字段或 getter 或 setter 方法上。

    您的 Java 类中的任何非扩展字段都是临时的。例如,您有一个带有 15 个字段的 Java 类,并注解了五个字段。生成的模式仅包含这五个字段,当将类实例存储在 Data Grid 中时,只有五个字段会被处理。

  2. 使用 @ProtoFactory 为不可变对象注解构造器。注解的构造器必须初始化使用 @ProtoField 注解的所有字段。
  3. 使用 @ProtoEnumValue 注解任何 Java enum 的成员。

以下 Author.javaBook.java 示例显示了使用 @ProtoField@ProtoFactory 注解的 Java 类:

Author.java

import org.infinispan.protostream.annotations.ProtoFactory;
import org.infinispan.protostream.annotations.ProtoField;

public class Author {
   @ProtoField(1)
   final String name;

   @ProtoField(2)
   final String surname;

   @ProtoFactory
   Author(String name, String surname) {
      this.name = name;
      this.surname = surname;
   }
   // public Getter methods omitted for brevity
}

Book.java

import org.infinispan.protostream.annotations.ProtoFactory;
import org.infinispan.protostream.annotations.ProtoField;

public class Book {
   @ProtoField(number = 1)
   public final UUID id;

   @ProtoField(number = 2)
   final String title;

   @ProtoField(number = 3)
   final String description;

   @ProtoField(number = 4, defaultValue = "0")
   final int publicationYear;

   @ProtoField(number = 5, collectionImplementation = ArrayList.class)
   final List<Author> authors;

   @ProtoField(number = 6)
   public Language language;

   @ProtoFactory
   Book(UUID id, String title, String description, int publicationYear, List<Author> authors, Language language) {
      this.id = id;
      this.title = title;
      this.description = description;
      this.publicationYear = publicationYear;
      this.authors = authors;
      this.language = language;
   }
   // public Getter methods not included for brevity
}

以下 Language.java 示例显示了一个带有 @ProtoEnumValue 注解的 Java enum,以及对应的 Protobuf 模式:

Language.java

import org.infinispan.protostream.annotations.ProtoEnumValue;

public enum Language {
  @ProtoEnumValue(number = 0, name = "EN")
  ENGLISH,
  @ProtoEnumValue(number = 1, name = "DE")
  GERMAN,
  @ProtoEnumValue(number = 2, name = "IT")
  ITALIAN,
  @ProtoEnumValue(number = 3, name = "ES")
  SPANISH,
  @ProtoEnumValue(number = 4, name = "FR")
  FRENCH;

}

Language.proto

enum Language {

   EN = 0;

   DE = 1;

   IT = 2;

   ES = 3;

   FR = 4;
}

2.2.3. 创建 ProtoStream 适配器类

ProtoStream 提供了一个 @ProtoAdapter 注释,您可以使用它来编译您无法直接注解的外部第三方 Java 对象类。

流程

  1. 创建一个 适配器 类并添加 @ProtoAdapter 注解,如下例所示:

    import java.util.UUID;
    
    import org.infinispan.protostream.annotations.ProtoAdapter;
    import org.infinispan.protostream.annotations.ProtoFactory;
    import org.infinispan.protostream.annotations.ProtoField;
    import org.infinispan.protostream.descriptors.Type;
    
    /**
     * Human readable UUID adapter for UUID marshalling
     */
    @ProtoAdapter(UUID.class)
    public class UUIDAdapter {
    
      @ProtoFactory
      UUID create(String stringUUID) {
        return UUID.fromString(stringUUID);
      }
    
      @ProtoField(1)
      String getStringUUID(UUID uuid) {
        return uuid.toString();
      }
    }

2.2.4. 生成序列化上下文初始化器

添加 ProtoStream 处理器并注解 Java 类后,您可以将 @AutoProtoSchemaBuilder 注解添加到接口,以便数据仓库生成 Protobuf 模式、marshallers 以及 SerializationContextInitializer 的聚合实现。

注意

默认情况下,生成的实现名称是注解的类名称,带有一个 "Impl" 后缀。

流程

  1. 定义一个扩展 GeneratedSchema 或其超级接口 SerializationContextInitializer 的接口。

    注意

    GeneratedSchema 接口包括访问 Protobuf 模式的方法,而 SerializationContextInitializer 接口只支持注册方法。

  2. 使用 @AutoProtoSchemaBuilder 注解接口。
  3. 确保 includeClasses 参数包含生成的 SerializationContextInitializer 实现的所有类。
  4. 使用 schemaFileName 参数为生成的 .proto 模式指定一个名称。
  5. target/classes 下设置一个路径,其中 schema 文件使用 schemaFilePath 参数生成。
  6. 使用 schemaPackageName 参数为生成的 .proto 模式指定软件包名称。

以下示例显示了使用 @AutoProtoSchemaBuilder 注解的 GeneratedSchema 接口:

@AutoProtoSchemaBuilder(
      includeClasses = {
            Book.class,
            Author.class,
            UUIDAdapter.class,
            Language.class
      },
      schemaFileName = "library.proto",
      schemaFilePath = "proto/",
      schemaPackageName = "book_sample")
interface LibraryInitializer extends GeneratedSchema {
}

后续步骤

如果您使用嵌入式缓存,Data Grid 会自动注册您的 SerializationContextInitializer 实现。

如果使用远程缓存,您必须在 Data Grid Server 中注册 SerializationContextInitializer 实现。

2.2.5. 注册序列化上下文初始化器

对于嵌入式缓存,Data Grid 会自动使用 java.util.ServiceLoader 在注解的 SerializationContextInitializer 实现中注册序列化上下文和 marshallers。

如果您希望禁用 SerializationContextInitializer 实现的自动注册,然后手动注册它们。

重要

如果您手动注册一个 SerializationContextInitializer 实现,它会禁用自动注册。然后,您必须手动注册所有其他实现。

流程

  1. AutoProtoSchemaBuilder.service 注解设置 false 值。

    @AutoProtoSchemaBuilder(
          includeClasses = SomeClass.class,
          ...
          service = false
    )
  2. 手动以编程方式或声明性地注册 SerializationContextInitializer 实现,如下例所示:

声明

<serialization>
    <context-initializer class="org.infinispan.example.LibraryInitializerImpl"/>
    <context-initializer class="org.infinispan.example.another.SCIImpl"/>
</serialization>

programmatic

GlobalConfigurationBuilder builder = new GlobalConfigurationBuilder();
builder.serialization()
       .addContextInitializers(new LibraryInitializerImpl(), new SCIImpl());

2.2.6. 将 Protobuf 模式注册到 Data Grid 服务器

使用 Data Grid Server 注册 Protobuf 模式,以执行 Ickle 查询或从 application/x-protostream 转换到其他介质类型,如 application/json

先决条件

  • 使用 ProtoStream 处理器生成 Protobuf 模式。

    您可以在 target/<schemaFilePath>/ 目录中找到生成的 Protobuf 模式。

  • 具有 CREATE 权限的用户。

    注意

    安全授权需要 CREATE 权限来添加模式。使用默认设置时,您至少需要 deployer 角色。

流程

使用以下方法之一在 Data Grid 服务器中添加 Protobuf 模式:

  • 在任何浏览器中打开 Data Grid Console,选择 Schema 选项卡,然后添加 Protobuf 模式
  • 使用带有 Data Grid 命令行界面(CLI)中的 --upload= 参数的 schema 命令。

    schema --upload=person.proto person
  • 使用 REST API 在 POST 请求有效负载中包含 Protobuf 模式。

    POST/rest/v2/schemas/<schema_name>
  • 使用带有 Hot Rod 客户端生成的 SerializationContextInitializer 实现来注册 Protobuf 模式,如下例所示:

    /**
     * Register generated Protobuf schema with Data Grid Server.
     * This requires the RemoteCacheManager to be initialized.
     *
     * @param initializer The serialization context initializer for the schema.
     */
    private void registerSchemas(SerializationContextInitializer initializer) {
      // Store schemas in the '___protobuf_metadata' cache to register them.
      // Using ProtobufMetadataManagerConstants might require the query dependency.
      final RemoteCache<String, String> protoMetadataCache = remoteCacheManager.getCache(ProtobufMetadataManagerConstants.PROTOBUF_METADATA_CACHE_NAME);
      // Add the generated schema to the cache.
      protoMetadataCache.put(initializer.getProtoFileName(), initializer.getProtoFile());
    
      // Ensure the registered Protobuf schemas do not contain errors.
      // Throw an exception if errors exist.
      String errors = protoMetadataCache.get(ProtobufMetadataManagerConstants.ERRORS_KEY_SUFFIX);
      if (errors != null) {
        throw new IllegalStateException("Some Protobuf schema files contain errors: " + errors + "\nSchema :\n" + initializer.getProtoFileName());
      }
    }
  • 添加带有 SerializationContextInitializer 实现的 JAR 文件,并将自定义类添加到 $114G_HOME/server/lib 目录中。

    当您执行此操作时,Data Grid 服务器在启动时注册您的 Protobuf 模式。但是,您必须将存档添加到每台服务器安装中,因为 schema 不会保存在 ___protobuf_metadata 缓存中,或者在集群中自动分发。

    注意

    如果您需要 Data Grid Server 执行任何 application/x-protostreamapplication/x-java-object 转换,则必须执行此操作,在这种情况下,您必须为 POJO 添加任何 JAR 文件。

后续步骤

SerializationContextInitializer 注册到 Hot Rod 客户端,如下例所示:

ConfigurationBuilder remoteBuilder = new ConfigurationBuilder();
remoteBuilder.addServer().host(host).port(Integer.parseInt(port));

// Add your generated SerializationContextInitializer implementation.
LibraryInitalizer initializer = new LibraryInitalizerImpl();
remoteBuilder.addContextInitializer(initializer);

2.2.7. 手动序列化上下文初始化器实现

重要

Data Grid 强烈建议您手动实现 SerializationContextInitializerGeneratedSchema 接口。

可以使用 ProtobufTagMarshallerRawProtobufMarshaller 注解手动实现 SerializationContextInitializerGeneratedSchema 接口。

但是,手动实施需要大量的开销,且容易出错。使用 protostream-processor 工件生成的实现更为高效且可靠的方法来配置 ProtoStream marshalling。

Red Hat logoGithubRedditYoutubeTwitter

学习

尝试、购买和销售

社区

关于红帽文档

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

让开源更具包容性

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

關於紅帽

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

© 2024 Red Hat, Inc.