您好 ChronicleMap 用户,
我正在尝试将 ChronicleMap 与自定义键和值一起使用。 Key 由各种输入组成,Value 是数据库查找的结果。我想将其存储在内存中以加快后续请求的速度。然而,我正在努力决定键和值序列化器应该采用什么方法。这是我的 Key 和 Value,基本 Key 是 CacheKey,实现是 NetKey;我有几个不同的键可供使用。我尝试了几个选项,但似乎无法序列化/反序列化我的键/值。
public interface CacheKey extends Serializable {
byte[] getKey();
void setKey(Object object);
}
public interface CacheValue extends Serializable {
byte[] getValue();
void setValue(Object object);
}
@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;
}
}
//... override equals and hashCode
}
@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;
}
}
// override equals and 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 need help to implement this method
}
@Override
public void write(Bytes out, @NotNull CacheValue toWrite) {
// TODO need help to implement this method
}
}
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
我看到的错误是 StackOverflow
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)
我能够通过将键和值更改为 Class 并使用自定义序列化器来解决此问题。
@Getter
@Setter
@SuperBuilder
class NetKey extends CacheKey {
private String productType;
private String dealDate;
@Override
public boolean equals(Object object) {
if (this == object) return true;
if (object == null || getClass() != object.getClass()) return false;
NetKey nk = (NetKey) object;
return super.equals(object) &&
(isEmpty(this.productType) || Objects.equals(this.productType, nk.productType)) &&
Objects.equals(this.dealDate, nk.dealDate);
}
@Override
public int hashCode() {
return Objects.hash(super.hashCode(), productType, dealDate);
}
@Override
public String toString() {
return "NetKey{" +
super.toString() +
", productType='" + productType + '\'' +
", dealDate='" + dealDate + '\'' +
'}';
}
}
@Setter
@Getter
@SuperBuilder
class CacheKey {
private String cacheType;
@Override
public boolean equals(Object object) {
if (this == object) return true;
if (object == null || getClass() != object.getClass()) return false;
CacheKey na = (CacheKey) object;
return Objects.equals(this.cacheType, na.cacheType);
}
@Override
public int hashCode() {
return Objects.hash(cacheType);
}
@Override
public String toString() {
return "CacheKey{" +
"cacheType='" + cacheType + '\'' +
'}';
}
}
@SuperBuilder
@Getter
@Setter
class NetValue extends CacheValue {
private String entity;
private String group;
private String service;
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
NetValue that = (NetValue) o;
return super.equals(o) &&
Objects.equals(entity, that.entity) &&
Objects.equals(group, that.group) &&
Objects.equals(service, this.service);
}
@Override
public int hashCode() {
return Objects.hash(entity, group, service);
}
@Override
public String toString() {
return "NetValue{" +
"entity='" + entity + '\'' +
", group='" + group + '\'' +
", service=" + service +
'}';
}
}
@SuperBuilder
@Getter
@Setter
class CacheValue {
private String cacheType;
@Override
public boolean equals(Object object) {
if (this == object) return true;
if (object == null || getClass() != object.getClass()) return false;
CacheValue na = (CacheValue) object;
return Objects.equals(this.cacheType, na.cacheType);
}
@Override
public int hashCode() {
return Objects.hash(cacheType);
}
@Override
public String toString() {
return "CacheValue{" +
"cacheType='" + cacheType + '\'' +
'}';
}
}
class CacheKeyMarshaller implements BytesReader<CacheKey>, BytesWriter<CacheKey> {
public static CacheKeyMarshaller INSTANCE = new CacheKeyMarshaller();
private CacheKeyMarshaller() {
}
@Override
public CacheKey read(Bytes in, CacheKey using) throws IllegalStateException {
String cacheType = in.readUtf8();
CacheType cache = CacheType.valueOf(cacheType);
if (cache == CacheType.NETTING) {
return readNetKey(in, using, cacheType);
} else {
using = readCacheKey(in, using, cacheType);
}
return using;
}
@Override
public void write(Bytes out, CacheKey toWrite) {
CacheType cache = CacheType.valueOf(toWrite.getCacheType());
if (cache == CacheType.NETTING) {
writeNetKey(out, (NetKey) toWrite);
} else {
writeCacheKey(out, toWrite);
}
}
private CacheKey readCacheKey(Bytes in, CacheKey using, String cacheType) {
if (using == null) {
using = CacheKey.builder().cacheType(cacheType).build();
} else {
using.setCacheType(cacheType);
}
return using;
}
private NetKey readNetKey(Bytes in, CacheKey using, String cacheType) {
String productType = in.readUtf8();
String dealDate = in.readUtf8();
NetKey value;
if (using == null) {
value = NetKey.builder().cacheType(cacheType)
.productType(productType)
.dealDate(dealDate)
.build();
} else {
value = (NetKey) using;
value.setCacheType(cacheType);
value.setProductType(productType);
value.setDealDate(dealDate);
}
return value;
}
private void writeCacheKey(Bytes out, CacheKey toWrite) {
out.writeUtf8(toWrite.getCacheType());
}
private void writeNetKey(Bytes out, NetKey toWrite) {
out.writeUtf8(toWrite.getCacheType());
out.writeUtf8(toWrite.getProductType());
out.writeUtf8(toWrite.getDealDate());
}
}
class CacheValueMarshaller implements BytesReader<CacheValue>, BytesWriter<CacheValue> {
public static CacheValueMarshaller INSTANCE = new CacheValueMarshaller();
private CacheValueMarshaller() {
}
@Override
public void write(Bytes out, CacheValue toWrite) {
String cacheType = toWrite.getCacheType();
CacheType cache = CacheType.valueOf(cacheType);
if (cache == CacheType.NETTING) {
writeNetValue(out, (NetValue) toWrite, cacheType);
} else {
writeCacheValue(out, toWrite);
}
}
@Override
public CacheValue read(Bytes in, CacheValue using) {
String cacheType = in.readUtf8();
CacheType cache = CacheType.valueOf(cacheType);
if (cache == CacheType.NETTING) {
return readNetValue(in, (NetValue) using, cacheType);
} else {
return readValueBase(in, using, cacheType);
}
}
private NetValue readNetValue(Bytes in, NetValue using, String cacheType) {
if (using == null) {
using = NetValue.builder().cacheType(cacheType)
.entity(in.readUtf8())
.group(in.readUtf8())
.service(in.readUtf8())
.build();
} else {
using.setCacheType(cacheType);
using.setEntity(in.readUtf8());
using.setGroup(in.readUtf8());
using.setService(in.readUtf8());
}
return using;
}
private CacheValue readValueBase(Bytes in, CacheValue using, String cacheType) {
if (using == null) {
using = CacheValue.builder().cacheType(cacheType).build();
} else {
using.setCacheType(cacheType);
}
return using;
}
private void writeNetValue(Bytes out, NetValue toWrite, String cacheType) {
out.writeUtf8(cacheType);
out.writeUtf8(toWrite.getEntity());
out.writeUtf8(toWrite.getGroup());
out.writeUtf8(toWrite.getService());
}
private void writeCacheValue(Bytes out, CacheValue toWrite) {
out.writeUtf8(toWrite.getCacheType());
}
}
public class Test {
public static void main(String[] args) {
ChronicleMap<CacheKey, CacheValue> map = null;
try {
NetKey key = NetKey.builder().cacheType(CacheType.NETTING.name())
.productType("type")
.dealDate("2023-04-23")
.build();
NetValue value = NetValue.builder().cacheType(CacheType.NETTING.name())
.entity("entity")
.group("group")
.service("service")
.build();
map = ChronicleMap.of(CacheKey.class, CacheValue.class)
.name("Sample-map")
.entries(50)
.averageKey(key)
.averageValue(value)
.keyMarshaller(CacheKeyMarshaller.INSTANCE)
.valueMarshaller(CacheValueMarshaller.INSTANCE)
.create();
map.put(key, value);
map.forEach((key1, value1) -> System.out.println(key1 + "->" + value1));
} finally {
if (map != null) map.close();
}
}
}