
在使用Hazelcast 4.2.5版本的ReplicatedMap,并将其配置为InMemoryFormat.BINARY时,应用程序日志中频繁出现java.lang.ClassCastException: class java.lang.String cannot be cast to class com.hazelcast.internal.serialization.impl.HeapData错误。此异常通常发生在Hazelcast的内部指标收集线程中,具体堆栈信息如下:
java.lang.ClassCastException: class java.lang.String cannot be cast to class com.hazelcast.internal.serialization.impl.HeapData (...)
at com.hazelcast.replicatedmap.impl.LocalReplicatedMapStatsProvider.getLocalReplicatedMapStats(LocalReplicatedMapStatsProvider.java:85)
at com.hazelcast.replicatedmap.impl.ReplicatedMapService.getLocalReplicatedMapStats(ReplicatedMapService.java:197)
at com.hazelcast.replicatedmap.impl.ReplicatedMapService.getStats(ReplicatedMapService.java:357)
at com.hazelcast.replicatedmap.impl.ReplicatedMapService.provideDynamicMetrics(ReplicatedMapService.java:387)
at com.hazelcast.internal.metrics.impl.MetricsCollectionCycle.collectDynamicMetrics(MetricsCollectionCycle.java:88)
... (metrics collection related stack trace)错误发生在LocalReplicatedMapStatsProvider尝试计算内存使用量时,它预期获取HeapData类型的数据进行操作,但实际获取到了String类型,导致类型转换失败。
当前的Hazelcast配置示例如下:
import com.hazelcast.config.Config;
import com.hazelcast.config.InMemoryFormat;
import com.hazelcast.config.JoinConfig;
import com.hazelcast.config.NetworkConfig;
import com.hazelcast.config.ReplicatedMapConfig;
import com.hazelcast.core.Hazelcast;
import com.hazelcast.core.HazelcastInstance;
import com.hazelcast.replicatedmap.ReplicatedMap;
public class HazelcastConfigExample {
private static HazelcastInstance setupHazelcastConfig() {
Config config = new Config();
config.setInstanceName("rogueUsers");
NetworkConfig network = config.getNetworkConfig();
network.setPort(5701).setPortCount(20);
network.setPortAutoIncrement(true);
JoinConfig join = network.getJoin();
join.getMulticastConfig().setEnabled(true);
HazelcastInstance hz = Hazelcast.getOrCreateHazelcastInstance(config);
ReplicatedMapConfig replicatedMapConfig =
config.getReplicatedMapConfig("rogueUsers");
replicatedMapConfig.setInMemoryFormat(InMemoryFormat.BINARY); // <-- 配置为BINARY
replicatedMapConfig.setAsyncFillup(true);
replicatedMapConfig.setStatisticsEnabled(true); // <-- 开启了统计
replicatedMapConfig.setSplitBrainProtectionName("splitbrainprotection-name");
// 问题所在:此处泛型为 String, String
ReplicatedMap<String, String> map = hz.getReplicatedMap("rogueUsers");
// map.addEntryListener(new RogueEntryListener()); // 假设有监听器
return hz;
}
}此ClassCastException的根本原因在于对InMemoryFormat.BINARY的理解与ReplicatedMap泛型类型声明之间的不匹配。
根据Hazelcast的com.hazelcast.internal.serialization.Data类Javadoc,Data是序列化的基本单元,它存储了对象经SerializationService.toData(Object)序列化后的二进制形式。因此,当InMemoryFormat.BINARY生效时,内部操作理应处理Data类型。
要解决此ClassCastException,需要确保ReplicatedMap的泛型类型与InMemoryFormat.BINARY所指示的内部存储格式保持一致。这意味着,当数据以二进制形式存储时,ReplicatedMap的键和值类型都应该声明为Data。
将ReplicatedMap的声明从ReplicatedMap<String, String>修改为ReplicatedMap<Data, Data>:
import com.hazelcast.config.Config;
import com.hazelcast.config.InMemoryFormat;
import com.hazelcast.config.JoinConfig;
import com.hazelcast.config.NetworkConfig;
import com.hazelcast.config.ReplicatedMapConfig;
import com.hazelcast.core.Hazelcast;
import com.hazelcast.core.HazelcastInstance;
import com.hazelcast.replicatedmap.ReplicatedMap;
import com.hazelcast.internal.serialization.Data; // 导入 Data 类
import com.hazelcast.spi.serialization.SerializationService; // 可能需要,用于手动序列化
public class HazelcastConfigFixedExample {
private static HazelcastInstance setupHazelcastConfig() {
Config config = new Config();
config.setInstanceName("rogueUsers");
NetworkConfig network = config.getNetworkConfig();
network.setPort(5701).setPortCount(20);
network.setPortAutoIncrement(true);
JoinConfig join = network.getJoin();
join.getMulticastConfig().setEnabled(true);
HazelcastInstance hz = Hazelcast.getOrCreateHazelcastInstance(config);
ReplicatedMapConfig replicatedMapConfig =
config.getReplicatedMapConfig("rogueUsers");
replicatedMapConfig.setInMemoryFormat(InMemoryFormat.BINARY);
replicatedMapConfig.setAsyncFillup(true);
replicatedMapConfig.setStatisticsEnabled(true);
replicatedMapConfig.setSplitBrainProtectionName("splitbrainprotection-name");
// 修正:将泛型类型改为 Data, Data
ReplicatedMap<Data, Data> map = hz.getReplicatedMap("rogueUsers");
// map.addEntryListener(new RogueEntryListener()); // 监听器可能需要调整以处理 Data 类型
return hz;
}
}将ReplicatedMap的泛型类型从String, String改为Data, Data虽然可以解决ClassCastException,但这会改变应用程序与ReplicatedMap交互的方式。
数据存取方式改变:
之前: 您可以直接存入和取出String对象,Hazelcast会透明地处理序列化和反序列化。
// 之前
ReplicatedMap<String, String> map = hz.getReplicatedMap("rogueUsers");
map.put("key1", "value1");
String value = map.get("key1");之后: 您需要手动将要存储的String或其他对象序列化为Data对象,再存入Map。同样,从Map中取出的是Data对象,需要手动反序列化回原始类型。
// 之后
ReplicatedMap<Data, Data> map = hz.getReplicatedMap("rogueUsers");
// 获取Hazelcast的序列化服务
SerializationService serializationService = ((HazelcastInstanceProxy) hz).getSerializationService();
// 存入数据
Data keyData = serializationService.toData("key1");
Data valueData = serializationService.toData("value1");
map.put(keyData, valueData);
// 取出数据
Data retrievedValueData = map.get(keyData);
String retrievedValue = serializationService.toObject(retrievedValueData);这会增加应用程序代码的复杂性,因为您现在需要直接处理Hazelcast的内部Data类型。
监听器(EntryListener)的影响: 如果您注册了EntryListener,其onEntryEvent方法接收的键和
以上就是解决Hazelcast ReplicatedMap ClassCastException:BINARY 存储格式的正确使用的详细内容,更多请关注php中文网其它相关文章!
每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号