如何为Infinispan缓存序列化Bucket4j的LockFreeBucket?
解决Bucket4j LockFreeBucket存入Infinispan RemoteCache的序列化问题
问题重现
尝试将Bucket4j的LockFreeBucket对象存入Infinispan远程缓存时,执行cache.put(key, bucket)抛出序列化异常:
org.infinispan.client.hotrod.exceptions.HotRodClientException:: Unable to marshall object of type [io.github.bucket4j.local.LockFreeBucket]
根因是LockFreeBucket未实现java.io.Serializable接口,即便配置了Java序列化白名单也无法解决。
相关代码:
限流器逻辑
public boolean isRateLimited(String key) { Bucket bucket = cacheManager.getCache("rate-limiter").get(key, Bucket.class); if (bucket == null) { bucket = bucketSupplier.get(); Cache<String, Bucket> cache = cacheManager.getCache("rate-limiter"); cache.put(key, bucket); } return !bucket.tryConsume(1); }
RemoteCacheManager配置
@Bean public RemoteCacheManager getRemoteCacheManager() { ConfigurationBuilder configurationBuilder = new ConfigurationBuilder(); configurationBuilder .addServer() .host("somehost") .port(11222) .marshaller(new JavaSerializationMarshaller()) .addJavaSerialWhiteList("io.github.bucket4j.*") .security() .ssl() .sniHostName("infinispan") .trustStoreFileName("./cacerts 2") .trustStorePassword("changeit".toCharArray()) .authentication() .username("some") .password("somepassword") .addContextInitializer(new CreateProtoImpl()) .clientIntelligence(ClientIntelligence.BASIC); return new RemoteCacheManager(configurationBuilder.build()); }
解决方案
方案1:使用Bucket4j官方Infinispan扩展(推荐)
Bucket4j提供了专门适配Infinispan的模块,无需手动处理LockFreeBucket的序列化,直接基于缓存状态构建Bucket。
添加依赖
引入Bucket4j的Infinispan扩展包(版本请匹配你的Bucket4j和Infinispan版本):<dependency> <groupId>com.github.vladimir-bukhtoyarov</groupId> <artifactId>bucket4j-infinispan</artifactId> <version>4.10.0</version> </dependency>修改限流器代码
改用Bucket4j的Infinispan扩展创建Bucket,直接复用远程缓存存储Bucket状态:import io.github.bucket4j.Bucket; import io.github.bucket4j.Bucket4j; import io.github.bucket4j.Bandwidth; import io.github.bucket4j.infinispan.Infinispan; import org.infinispan.client.hotrod.RemoteCache; public boolean isRateLimited(String key) { // 获取远程缓存实例 RemoteCache<String, GridBucketState> cache = cacheManager.getCache("rate-limiter"); // 基于Infinispan缓存构建Bucket Bucket bucket = Bucket4j.extension(Infinispan.class) .builder() // 替换为你的限流规则(示例:1分钟10次请求) .addLimit(Bandwidth.simple(10, java.time.Duration.ofMinutes(1))) // 从缓存加载或创建Bucket状态,不存在则重建 .build(cache, key, RecoveryStrategy.RECONSTRUCT); return !bucket.tryConsume(1); }调整序列化白名单
由于存储的是GridBucketState(Bucket4j的分布式状态对象),需将其包路径加入白名单:configurationBuilder.addJavaSerialWhiteList("com.github.vladimir_bukhtoyarov.bucket4j.grid.*");
方案2:自定义序列化(不推荐)
若无法使用官方扩展,需为LockFreeBucket实现自定义序列化逻辑,比如通过Infinispan的AdvancedExternalizer接口解析其内部状态。但此方法依赖LockFreeBucket的私有字段,后续版本可能失效,维护成本高,不建议采用。
内容的提问来源于stack exchange,提问作者Tirumalesh
相关产品推荐
相关产品推荐

