5.2. 将应用程序迁移到 AutoProtoSchemaBuilder 注解
之前的 Data Grid 版本使用 ProtoStream API 中的 MessageMarshaller 接口来配置 marshalling。
MessageMarshaller API 和 ProtoSchemaBuilder 注解都从 Data Grid 8.1.1 中弃用,它对应于 ProtoStream 4.3.4。
使用 MessageMarshaller 接口涉及:
- 手动创建 Protobuf 模式。
-
将
ProtoSchemaBuilder注释添加到 Java 类,然后生成 Protobuf 模式。
但是,配置 ProtoStream marshalling 的这些技术不作为 AutoProtoSchemaBuilder 注释(可从 Data Grid 81 开始获得)。只需在您的 Java 类中添加 AutoProtoSchemaBuilder 注释,并生成包含 Protobuf 模式和相关 marshallers 的 SerializationContextInitializer 实现。
红帽建议您开始使用 AutoProtoSchemaBuilder 注解从 ProtoStream marshaller 获取最佳结果。
以下代码示例演示了如何将应用从 MessageMarshaller API 迁移到 AutoProtoSchemaBuilder 注释。
5.2.1. 基本 MessageMarshaller 实现 复制链接链接已复制到粘贴板!
这个示例包含使用非默认类型的一些字段。text 字段有不同的顺序,固定32 字段与生成的 Protobuf 模式类型冲突,因为代码生成器默认使用 int 类型。
SimpleEntry.java
public class SimpleEntry {
private String description;
private Collection<String> text;
private int intDefault;
private Integer fixed32;
// public Getter, Setter, equals and HashCode methods omitted for brevity
}
SimpleEntryMarshaller.java
import org.infinispan.protostream.MessageMarshaller;
public class SimpleEntryMarshaller implements MessageMarshaller<SimpleEntry> {
@Override
public void writeTo(ProtoStreamWriter writer, SimpleEntry testEntry) throws IOException {
writer.writeString("description", testEntry.getDescription());
writer.writeInt("intDefault", testEntry.getIntDefault());
writer.writeInt("fix32", testEntry.getFixed32());
writer.writeCollection("text", testEntry.getText(), String.class);
}
@Override
public SimpleEntry readFrom(MessageMarshaller.ProtoStreamReader reader) throws IOException {
SimpleEntry x = new SimpleEntry();
x.setDescription(reader.readString("description"));
x.setIntDefault(reader.readInt("intDefault"));
x.setFixed32(reader.readInt("fix32"));
x.setText(reader.readCollection("text", new LinkedList<String>(), String.class));
return x;
}
}
生成的 Protobuf 模式
syntax = "proto2";
package example;
message SimpleEntry {
required string description = 1;
optional int32 intDefault = 2;
optional fixed32 fix32 = 3;
repeated string text = 4;
}
迁移到 AutoProtoSchemaBuilder 注解
SimpleEntry.java
import org.infinispan.protostream.annotations.ProtoField;
import org.infinispan.protostream.descriptors.Type;
public class SimpleEntry {
private String description;
private Collection<String> text;
private int intDefault;
private Integer fixed32;
@ProtoField(number = 1)
public String getDescription() {...}
@ProtoField(number = 4, collectionImplementation = LinkedList.class)
public Collection<String> getText() {...}
@ProtoField(number = 2, defaultValue = "0")
public int getIntDefault() {...}
@ProtoField(number = 3, type = Type.FIXED32)
public Integer getFixed32() {...}
// public Getter, Setter, equals and HashCode methods and convenient constructors omitted for brevity
}
SimpleEntryInitializer.java
import org.infinispan.protostream.GeneratedSchema;
import org.infinispan.protostream.annotations.AutoProtoSchemaBuilder;
@AutoProtoSchemaBuilder(includeClasses = { SimpleEntry.class }, schemaFileName = "simple.proto", schemaFilePath = "proto", schemaPackageName = "example")
public interface SimpleEntryInitializer extends GeneratedSchema {
}
重要观察
-
字段 2 定义为
int,之前版本中的 ProtoStream marshaller 没有检查。 因为 Java
int字段不可为空,因此 ProtoStream 处理器将失败。
必须需要Javaint字段,或使用defaultValue进行初始化。从 Java 应用程序的角度来看,
int字段使用 "0" 初始化,因此您可以使用defaultValue,而不影响任何 put 操作会设置它。如果始终存在数据视角,则更改为必需不是问题,但可能会导致不同的客户端出现问题。-
为了兼容性,字段 3 必须明确设置为
Type.FIXED32。 - 对于生成的 Protobuf 模式,必须以正确的顺序设置 文本集合。
Protobuf 模式中的 文本集合 顺序必须与迁移之前和之后相同。同样,您必须在迁移过程中设置 fixed32 类型。
如果没有,客户端应用程序可能会抛出以下异常,且无法启动:
Exception ( ISPN004034: Unable to unmarshall bytes )
在其他情况下,您可能会观察缓存的数据不完整或不准确。
5.2.2. 带有自定义类型的 MessageMarshaller 实现 复制链接链接已复制到粘贴板!
本节提供了 MessageMarshaller 实现迁移示例,其中包含 ProtoStream 没有原生处理的字段。
以下示例使用 BigInteger 类,但适用于任何类,即使是数据网格适配器或自定义类。
BigInteger 类不可变,因此没有参数结构。
CustomTypeEntry.java
import java.math.BigInteger;
public class CustomTypeEntry {
final String description;
final BigInteger bigInt;
// public Getter, Setter, equals and HashCode methods and convenient constructors omitted for brevity
}
CustomTypeEntryMarshaller.java
import org.infinispan.protostream.MessageMarshaller;
public class CustomTypeEntryMarshaller implements MessageMarshaller<CustomTypeEntry> {
@Override
public void writeTo(ProtoStreamWriter writer, CustomTypeEntry testEntry) throws IOException {
writer.writeString("description", testEntry.description);
writer.writeString("bigInt", testEntry.bigInt.toString());
}
@Override
public CustomTypeEntry readFrom(MessageMarshaller.ProtoStreamReader reader) throws IOException {
final String desc = reader.readString("description");
final BigInteger bInt = new BigInteger(reader.readString("bigInt"));
return new CustomTypeEntry(desc, bInt);
}
}
CustomTypeEntry.proto
syntax = "proto2";
package example;
message CustomTypeEntry {
required string description = 1;
required string bigInt = 2;
}
使用适配器类迁移的代码
您可以使用 ProtoAdapter 注解以生成 Protobuf 模式的方式 marshall CustomType 类,它与您使用 MessageMarshaller 实现创建的 Protobuf 模式兼容。
使用这个方法,您可以:
-
不得在
CustomTypeEntry类中添加注解。 -
创建一个
CustomTypeEntryAdapter类,它使用@ProtoAdapter注释来控制如何生成 Protobuf 模式和 marshaller。 包含
CustomTypeEntryAdapter类,并包含@AutoProtoSchemaBuilder注释。注意由于
AutoProtoSchemaBuilder注释不引用CustomTypeEntry类,因此该类中包含的任何注解都会被忽略。
以下示例显示了包含 CustomTypeEntry 类的 ProtoStream 注解的 CustomTypeEntryAdapter 类:
CustomTypeEntryAdapter.java
import java.math.BigInteger;
import org.infinispan.protostream.annotations.ProtoAdapter;
import org.infinispan.protostream.annotations.ProtoFactory;
import org.infinispan.protostream.annotations.ProtoField;
@ProtoAdapter(CustomTypeEntry.class)
public class CustomTypeEntryAdapter {
@ProtoFactory
public CustomTypeEntry create(String description, String bigInt) {
return new CustomTypeEntry(description, new BigInteger(bigInt));
}
@ProtoField(number = 1, required = true)
public String getDescription(CustomTypeEntry t) {
return t.description;
}
@ProtoField(number = 2, required = true)
public String getBigInt(CustomTypeEntry t) {
return t.bigInt.toString();
}
}
以下示例显示了带有 AutoProtoSchemaBuilder 注解的 SerializationContextInitializer,该注解引用 CustomTypeEntryAdapter 类:
CustomTypeEntryInitializer.java
import org.infinispan.protostream.GeneratedSchema;
import org.infinispan.protostream.annotations.AutoProtoSchemaBuilder;
@AutoProtoSchemaBuilder(includeClasses = { CustomTypeEntryAdapter.class },
schemaFileName = "custom.proto",
schemaFilePath = "proto",
schemaPackageName = "example")
public interface CustomTypeAdapterInitializer extends GeneratedSchema { }
在没有适配器类的情况下迁移的代码
您可以直接将 ProtoStream 注解添加到 CustomTypeEntry 类中,而不是创建适配器类。
在本例中,生成的 Protobuf 模式与通过 MessageMarshaller 接口添加的缓存中的数据不兼容,因为 BigInteger 是一个单独的消息。即使 adapter 字段写入相同的 String,也无法处理数据。
以下示例显示了直接包含 ProtoStream 注解的 CustomTypeEntry 类:
CustomTypeEntry.java
import java.math.BigInteger;
public class CustomTypeEntry {
@ProtoField(number = 1)
final String description;
@ProtoField(number = 2)
final BigInteger bigInt;
@ProtoFactory
public CustomTypeEntry(String description, BigInteger bigInt) {
this.description = description;
this.bigInt = bigInt;
}
// public Getter, Setter, equals and HashCode methods and convenient constructors omitted for brevity
}
以下示例显示了带有 AutoProtoSchemaBuilder 注解的 SerializationContextInitializer,该注解引用 CustomTypeEntry 和 BigIntegerAdapter 类:
CustomTypeEntryInitializer.java
import org.infinispan.protostream.GeneratedSchema;
import org.infinispan.protostream.annotations.AutoProtoSchemaBuilder;
import org.infinispan.protostream.types.java.math.BigIntegerAdapter;
@AutoProtoSchemaBuilder(includeClasses = { CustomTypeEntry.class,
BigIntegerAdapter.class },
schemaFileName = "customtype.proto",
schemaFilePath = "proto",
schemaPackageName = "example")
public interface CustomTypeInitializer extends GeneratedSchema { }
当您从前面的 SerializationContextInitializer 实现中生成 Protobuf 模式时,它会生成以下 Protobuf 模式:
CustomTypeEntry.proto
syntax = "proto2";
package example;
message BigInteger {
optional bytes bytes = 1;
}
message CustomTypeEntry {
optional string description = 1;
optional BigInteger bigInt = 2;
}