2.2. 创建序列化上下文初始化器
序列化上下文初始化程序可让您在 Data Grid 中注册以下内容:
- 描述用户类型的 protobuf 模式。
- 提供序列化和反序列化功能的 Marshallers。
在高级别中,您应该执行以下操作来创建序列化上下文初始化器:
- 在 Java 类中添加 ProtoStream 注解。
-
使用 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。
流程
使用
@ProtoField
注解您要 marshall 的 Java 字段,可以直接在字段或 getter 或 setter 方法上。您的 Java 类中的任何非扩展字段都是临时的。例如,您有一个带有 15 个字段的 Java 类,并注解了五个字段。生成的模式仅包含这五个字段,当将类实例存储在 Data Grid 中时,只有五个字段会被处理。
-
使用
@ProtoFactory
为不可变对象注解构造器。注解的构造器必须初始化使用@ProtoField
注解的所有字段。 -
使用
@ProtoEnumValue
注解任何 Java enum 的成员。
以下 Author.java
和 Book.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 对象类。
流程
创建一个
适配器
类并添加@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" 后缀。
流程
定义一个扩展
GeneratedSchema
或其超级接口SerializationContextInitializer
的接口。注意GeneratedSchema
接口包括访问 Protobuf 模式的方法,而SerializationContextInitializer
接口只支持注册方法。-
使用
@AutoProtoSchemaBuilder
注解接口。 -
确保
includeClasses
参数包含生成的SerializationContextInitializer
实现的所有类。 -
使用
schemaFileName
参数为生成的.proto
模式指定一个名称。 -
在
target/classes
下设置一个路径,其中 schema 文件使用schemaFilePath
参数生成。 -
使用
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
实现,它会禁用自动注册。然后,您必须手动注册所有其他实现。
流程
为
AutoProtoSchemaBuilder.service
注解设置false
值。@AutoProtoSchemaBuilder( includeClasses = SomeClass.class, ... service = false )
-
手动以编程方式或声明性地注册
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-protostream
到application/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 强烈建议您手动实现 SerializationContextInitializer
或 GeneratedSchema
接口。
可以使用 ProtobufTagMarshaller
和 RawProtobufMarshaller
注解手动实现 SerializationContextInitializer
或 GeneratedSchema
接口。
但是,手动实施需要大量的开销,且容易出错。使用 protostream-processor
工件生成的实现更为高效且可靠的方法来配置 ProtoStream marshalling。