ChronicleMap自定义Key/Value序列化器实现及栈溢出问题求助
ChronicleMap自定义Key/Value序列化问题及栈溢出错误解决
我正在尝试用ChronicleMap存储自定义Key和Value:Key基于基类CacheKey(包含NetKey等多个实现类),Value基于基类CacheValue(比如NetValue),目的是将数据库查询结果存入内存以加速后续请求,但卡在了序列化器实现上,还出现了栈溢出错误。
现有代码实现
基类定义
public interface CacheKey extends Serializable { byte[] getKey(); void setKey(Object object); } public interface CacheValue extends Serializable { byte[] getValue(); void setValue(Object object); }
Key实现类
@Builder public class NetKey implements CacheKey { private String name; private String productType; private String dealDate; @Override public byte[] getKey() { return Util.writeToByte(this); } @Override public void setKey(Object object) { if (object instanceof NetKey) { NetKey o = (NetKey) object; this.name = o.name; this.productType = o.productType; this.dealDate = o.dealDate; } } // 已重写equals和hashCode }
Value实现类
@Builder public class NetValue implements CacheValue { private String entity; private String group; private Service service; @Override public byte[] getValue() { return Util.writeToByte(this); } @Override public void setValue(Object object) { if (object instanceof NetValue) { NetValue o = (NetValue) object; this.entity = o.entity; this.group = o.group; this.service = o.service; } } // 已重写equals和hashCode }
序列化器实现
public class MyKeySerializer implements BytesReader<CacheKey>, BytesWriter<CacheKey> { private static MyKeySerializer INSTANCE = new MyKeySerializer(); public static MyKeySerializer getInstance() { return INSTANCE; } private MyKeySerializer() {} @NotNull @Override public CacheKey read(Bytes in, @Nullable CacheKey using) { if (using == null) { using = new CacheKey() { @Override public CacheKey getKey() { return this; } @Override public void setKey(CacheKey object) { } }; } int len = in.readInt(); Object object = Util.readFromByte(in.toByteArray()); using.setKey(object == null ? null : (CacheKey) object); return using; } @Override public void write(Bytes out, @NotNull CacheKey toWrite) { byte[] content = Util.writeToByte(toWrite.getKey()); out.writeInt(content.length); out.write(content); } } public class MyValueSerializer implements BytesReader<CacheValue>, BytesWriter<CacheValue> { private static MyValueSerializer INSTANCE = new MyValueSerializer(); public static MyValueSerializer getInstance() { return INSTANCE; } private MyValueSerializer() {} @NotNull @Override public CacheValue read(Bytes in, @Nullable CacheValue using) { // TODO 需要实现该方法 } @Override public void write(Bytes out, @NotNull CacheValue toWrite) { // TODO 需要实现该方法 } }
测试代码
public class Test { public static void main(String[] args) { NetKey netKey = ...; NetValue netValue = ...; ChronicleMap<CacheKey, CacheValue> inMemoryMap = ChronicleMap.of(CacheKey.class, CacheKey.class) .name("sample-map") .entries(50) .averageKey(netKey) .averageValue(netValue) .keyMarshallers(MyKeySerializer.class) .valueMarshallers(MyValueSerializer.class) .create(); inMemoryMap.put(netKey, netValue); } }
错误信息(更新1)
出现栈溢出错误:
Exception in thread "main" java.lang.StackOverflowError at java.base/java.lang.RuntimeException.<init>(RuntimeException.java:52) at java.base/java.lang.IllegalArgumentException.<init>(IllegalArgumentException.java:40) at java.base/java.util.regex.PatternSyntaxException.<init>(PatternSyntaxException.java:58) at java.base/java.util.regex.Pattern.error(Pattern.java:2028) at java.base/java.util.regex.Pattern.<init>(Pattern.java:1432) at java.base/java.util.regex.Pattern.compile(Pattern.java:1069) at java.base/java.util.regex.Pattern.matches(Pattern.java:1174) at java.base/java.lang.String.matches(String.java:2839) at net.openhft.chronicle.values.CodeTemplate.lambda$null$20(CodeTemplate.java:206) at java.base/java.util.stream.ReferencePipeline$2$1.accept(ReferencePipeline.java:178) at java.base/java.util.stream.ReferencePipeline$2$1.accept(ReferencePipeline.java:179) at java.base/java.util.TreeMap$KeySpliterator.tryAdvance(TreeMap.java:3088) at java.base/java.util.stream.ReferencePipeline.forEachWithCancel(ReferencePipeline.java:129) at java.base/java.util.stream.AbstractPipeline.copyIntoWithCancel(AbstractPipeline.java:527) at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:513) at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:499) at java.base/java.util.stream.FindOps$FindOp.evaluateSequential(FindOps.java:150) at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234) at java.base/java.util.stream.ReferencePipeline.findFirst(ReferencePipeline.java:647) at net.openhft.chronicle.values.CodeTemplate.lambda$methodsAndTemplatesByField$21(CodeTemplate.java:207) at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:197) at java.base/java.util.stream.ReferencePipeline$2$1.accept(ReferencePipeline.java:179) at java.base/java.util.stream.ReferencePipeline$2$1.accept(ReferencePipeline.java:179) at java.base/java.util.Spliterators$ArraySpliterator.forEachRemaining(Spliterators.java:992) at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:509) at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:499) at java.base/java.util.stream.ReduceOps$ReduceOp.evaluateSequential(ReduceOps.java:921) at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234) at java.base/java.util.stream.ReferencePipeline.collect(ReferencePipeline.java:682) at net.openhft.chronicle.values.CodeTemplate.methodsAndTemplatesByField(CodeTemplate.java:214) at net.openhft.chronicle.values.CodeTemplate.createValueModel(CodeTemplate.java:104) at net.openhft.chronicle.values.ValueModel$1.computeValue(ValueModel.java:46) at java.base/java.lang.ClassValue.getFromHashMap(ClassValue.java:228) at java.base/java.lang.ClassValue.getFromBackup(ClassValue.java:210)
问题分析与解决方案
1. 栈溢出错误根源
测试代码中创建ChronicleMap时,泛型参数写错:ChronicleMap.of(CacheKey.class, CacheKey.class),第二个参数应该是CacheValue.class。这个错误会导致ChronicleMap内部代码生成逻辑陷入循环,最终触发栈溢出。
2. 序列化器逻辑修正
现有序列化器存在循环序列化、数据读取错误等问题,以下是修正后的实现:
修正后的MyKeySerializer
public class MyKeySerializer implements BytesReader<CacheKey>, BytesWriter<CacheKey> { private static final MyKeySerializer INSTANCE = new MyKeySerializer(); public static MyKeySerializer getInstance() { return INSTANCE; } private MyKeySerializer() {} @NotNull @Override public CacheKey read(Bytes in, @Nullable CacheKey using) { // 读取类型标识,区分不同CacheKey实现类 int type = in.readInt(); byte[] data = new byte[in.readInt()]; in.read(data); Object obj = Util.readFromByte(data); if (using != null) { using.setKey(obj); return using; } return (CacheKey) obj; } @Override public void write(Bytes out, @NotNull CacheKey toWrite) { // 写入类型标识,NetKey用1,其他实现类可定义不同值 if (toWrite instanceof NetKey) { out.writeInt(1); } else { out.writeInt(0); // 默认类型标识 } // 直接序列化对象本身,避免循环调用getKey byte[] content = Util.writeToByte(toWrite); out.writeInt(content.length); out.write(content); } }
实现完整的MyValueSerializer
public class MyValueSerializer implements BytesReader<CacheValue>, BytesWriter<CacheValue> { private static final MyValueSerializer INSTANCE = new MyValueSerializer(); public static MyValueSerializer getInstance() { return INSTANCE; } private MyValueSerializer() {} @NotNull @Override public CacheValue read(Bytes in, @Nullable CacheValue using) { int type = in.readInt(); byte[] data = new byte[in.readInt()]; in.read(data); Object obj = Util.readFromByte(data); if (using != null) { using.setValue(obj); return using; } return (CacheValue) obj; } @Override public void write(Bytes out, @NotNull CacheValue toWrite) { if (toWrite instanceof NetValue) { out.writeInt(1); } else { out.writeInt(0); } byte[] content = Util.writeToByte(toWrite); out.writeInt(content.length); out.write(content); } }
3. 修正测试代码
public class Test { public static void main(String[] args) { NetKey netKey = NetKey.builder().name("test").productType("type1").dealDate("20240101").build(); NetValue netValue = NetValue.builder().entity("entity1").group("group1").service(new Service()).build(); ChronicleMap<CacheKey, CacheValue> inMemoryMap = ChronicleMap.of(CacheKey.class, CacheValue.class) .name("sample-map") .entries(50) .averageKey(netKey) .averageValue(netValue) .keyMarshaller(MyKeySerializer.getInstance()) .valueMarshaller(MyValueSerializer.getInstance()) .create(); inMemoryMap.put(netKey, netValue); } }
额外注意事项
- 确保
Util.writeToByte和Util.readFromByte基于Java序列化时,所有涉及的类(包括Service)都实现Serializable接口。 - 若后续新增
CacheKey/CacheValue实现类,需同步更新序列化器中的类型标识逻辑,避免反序列化时类型错误。
内容的提问来源于stack exchange,提问作者user2459396
相关产品推荐
相关产品推荐

