ignite序列化自定义
前言
ignite是一款分布式存算一体库,跟redis一样它也是基于内存运行的,所以性能表现极佳,而且相比于redis而言,它除了kv形式还可以使用表和sql,操作更为便捷。
一、为什么要自定义ignite的序列化逻辑?
在日前的工作中,使用ignite存算一体库时,由于我们的实体属性字段用了枚举类型,导致报错,排查后发现是序列化问题,改动实体属性类型工作量较大,所以选择自定义ignite序列化逻辑
二、实现步骤
1.定义序列化器
代码如下(示例):
// IgniteSerializer
//实现ignite的BinarySerializer接口
public class IgniteSerializer implements BinarySerializer {
private static final Map<String, TriConsumer<BinaryWriter, String, Object>> WRITER_MAP = new ConcurrentHashMap<>();
static {
WRITER_MAP.put("BigDecimal", (writer, fieldName, value) -> writer.writeDecimal(fieldName, (BigDecimal) value));
WRITER_MAP.put("Boolean", (writer, fieldName, value) -> writer.writeInt(fieldName, (boolean) value ? 1 : 0));
WRITER_MAP.put("Byte", (writer, fieldName, value) -> writer.writeByte(fieldName, (byte) value));
WRITER_MAP.put("Character", (writer, fieldName, value) -> writer.writeChar(fieldName, (char) value));
WRITER_MAP.put("Date", (writer, fieldName, value) -> writer.writeDate(fieldName, (Date) value));
WRITER_MAP.put("Double", (writer, fieldName, value) -> writer.writeDouble(fieldName, (double) value));
WRITER_MAP.put("Float", (writer, fieldName, value) -> writer.writeFloat(fieldName, (float) value));
WRITER_MAP.put("Enum", (writer, fieldName, value) -> writer.writeInt(fieldName, ((MapEnum) value).getKey()));
WRITER_MAP.put("Integer", (writer, fieldName, value) -> writer.writeInt(fieldName, (int) value));
WRITER_MAP.put("Long", (writer, fieldName, value) -> writer.writeLong(fieldName, (long) value));
WRITER_MAP.put("Short", (writer, fieldName, value) -> writer.writeShort(fieldName, (short) value));
WRITER_MAP.put("String", (writer, fieldName, value) -> writer.writeString(fieldName, (String) value));
WRITER_MAP.put("Time", (writer, fieldName, value) -> writer.writeTime(fieldName, (Time) value));
WRITER_MAP.put("Timestamp", (writer, fieldName, value) -> writer.writeTimestamp(fieldName, (Timestamp) value));
}
// 处理写逻辑
@Override
public void writeBinary(Object obj, BinaryWriter writer) throws BinaryObjectException {
var declaredFields = obj.getClass().getDeclaredFields();
for (Field field : declaredFields) {
field.setAccessible(true);
String fieldName = field.getName();
var fieldType = field.getType();
try {
var fieldVal = field.get(obj);
if (fieldVal != null) {
var writerMethod = WRITER_MAP.get(fieldType.getSimpleName());
if (writerMethod != null) {
writerMethod.accept(writer, fieldName, fieldVal);
}
}
} catch (IllegalAccessException e) {
throw new BinaryObjectException("Failed to write field: " + fieldName + " of type: " + fieldType, e);
}
}
}
// 处理读逻辑
@Override
public void readBinary(Object obj, BinaryReader reader) throws BinaryObjectException {
Set<Field> declaredFields = Arrays.stream(obj.getClass().getDeclaredFields()).collect(Collectors.toSet());
if (obj.getClass().getSuperclass() != null) {
declaredFields.addAll(
Arrays.stream(obj.getClass().getSuperclass().getDeclaredFields()).collect(Collectors.toSet()));
}
for (Field field : declaredFields) {
try {
field.setAccessible(true);
var fieldVal = reader.readObject(field.getName());
if (fieldVal == null) {
continue;
}
if (field.getType().isEnum()) {
Enum[] enumConstants = (Enum[]) field.getType().getEnumConstants();
for (Enum enumConstant : enumConstants) {
if (((MapEnum) enumConstant).getKey() == (int) fieldVal) {
field.set(obj, enumConstant);
}
}
} else if (field.getType() == Boolean.class) {
field.set(obj, fieldVal instanceof Boolean ? fieldVal :
Integer.parseInt(fieldVal.toString()) == 1 ? true : false);
} else {
field.set(obj, fieldVal);
}
} catch (IllegalAccessException e) {
throw new BinaryObjectException("Failed to read enum field: " + field.getName(), e);
}
}
}
}
2.指定ignite序列化器
代码如下(示例):
// IgniteThinClientConfig.java
@Bean
IgniteClientConfigurer configurer() {
return cfg -> {
// set self define serializer
BinaryConfiguration binaryCfg = new BinaryConfiguration();
binaryCfg.setSerializer(new IgniteSerializer());
cfg.setBinaryConfiguration(binaryCfg);
cfg.setPartitionAwarenessEnabled(true);
};
}
至此配置结束。
总结
通过配置自定义ignite序列化器完美解决了我们的困境。