我正在尝试将 Redisson 设置为用于bucket4j,并在 JVM 17 上运行我的 Spring Boot 2.7.3 应用程序。目前,我正在使用单元测试来让所有内容都在某个合理的水平上工作,但显然需要一个稍后真正实施。
进入代码...
@Configuration
@EnableCaching
public class Bucket4JConfig {
public static final String CACHE_NAME = "r_quota_";
@Bean
public Config envConfig() {
var port = "6379";
var host = "localhost";
BinaryOperator<String> getUrl = (h, p) -> String.format("redis://%s:%s", h, p);
Config config = new Config();
config.useReplicatedServers()
.setReadMode(ReadMode.SLAVE)
.addNodeAddress(getUrl.apply(host, port));
return config;
}
@Bean(name = "javaxCacheManager")
public CacheManager cacheManager() {
return Caching.getCachingProvider().getCacheManager();
}
@Bean
public ProxyManager<String> proxyManager(CacheManager cacheManager, Config config) {
Cache<String, byte[]> cache = cacheManager.getCache(CACHE_NAME);
if (cache == null) {
MutableConfiguration<String, byte[]> jcacheConfig = new MutableConfiguration<>();
jcacheConfig.setExpiryPolicyFactory(null); // never expire
javax.cache.configuration.Configuration<String, byte[]> redissonConfiguration = RedissonConfiguration.fromConfig(config, jcacheConfig);
cache = cacheManager.createCache(CACHE_NAME, redissonConfiguration);
}
return new JCacheProxyManager<>(cache);
}
@Bean
@Primary
public SyncCacheResolver bucket4jCacheResolver(CacheManager cacheManager) {
return new JCacheCacheResolver(cacheManager);
}
@Bean
public JCacheManagerCustomizer jCacheManagerCustomizer(Config config) {
return cacheManager -> cacheManager.createCache(CACHE_NAME, RedissonConfiguration.fromConfig(config));
}
}
@Service
public class RateLimitService {
private static final int QUOTA = 2;
private final ProxyManager<String> buckets;
public RateLimitService(ProxyManager<String> buckets) {
this.buckets = buckets;
}
public void blockOnBucket(String bucketName) throws InterruptedException {
resolveBucket(bucketName).asBlocking().consume(1);
}
private Bucket resolveBucket(String bucketName) {
Supplier<BucketConfiguration> confSupplier = () -> {
return BucketConfiguration.builder()
.addLimit(limit -> limit.capacity(QUOTA).refillGreedy(QUOTA, Duration.ofSeconds(1)))
.build();
};
return buckets.builder().build(bucketName, confSupplier);
}
}
public class Bucket4JOverRedissonTest {
private RateLimitService rateLimitService;
@BeforeEach
public void setUp() {
Bucket4JConfig conf = new Bucket4JConfig();
var config = conf.envConfig();
var cacheManager = conf.cacheManager();
System.out.printf("Caches: [%s]", Streams.stream(cacheManager.getCacheNames()).collect(Collectors.joining(",")));
rateLimitService = new RateLimitService(conf.proxyManager(cacheManager, config));
}
@Test
public void test() throws InterruptedException {
String bucketName = "LIMITED_RESOURCE";
StopWatch stopWatch = new StopWatch();
stopWatch.start();;
rateLimitService.blockOnBucket(bucketName);
rateLimitService.blockOnBucket(bucketName);
rateLimitService.blockOnBucket(bucketName);
stopWatch.stop();
Assertions.assertTrue(stopWatch.getTotalTimeMillis() > 1000);
}
}
我将这些行添加到我的 pom.xml 中:
<dependency>
<groupId>com.bucket4j</groupId>
<artifactId>bucket4j_jdk17-redis-common</artifactId>
<version>8.11.1</version>
</dependency>
<dependency>
<groupId>com.bucket4j</groupId>
<artifactId>bucket4j_jdk17-redisson</artifactId>
<version>8.11.1</version>
</dependency>
<dependency>
<groupId>com.giffing.bucket4j.spring.boot.starter</groupId>
<artifactId>bucket4j-spring-boot-starter</artifactId>
<version>0.12.6</version>
</dependency>
<dependency>
<groupId>org.redisson</groupId>
<artifactId>redisson-spring-boot-starter</artifactId>
<version>2.15.2</version>
</dependency>
我不断遇到异常:
java.lang.reflect.InaccessibleObjectException: Unable to make field private final byte[] java.lang.String.value accessible: module java.base does not "opens java.lang" to unnamed module @1d371b2d
at java.base/java.lang.reflect.AccessibleObject.checkCanSetAccessible(AccessibleObject.java:354)
at java.base/java.lang.reflect.AccessibleObject.checkCanSetAccessible(AccessibleObject.java:297)
at java.base/java.lang.reflect.Field.checkCanSetAccessible(Field.java:178)
at java.base/java.lang.reflect.Field.setAccessible(Field.java:172)
at org.nustaq.serialization.FSTClazzInfo.createFieldInfo(FSTClazzInfo.java:504)
at org.nustaq.serialization.FSTClazzInfo.createFields(FSTClazzInfo.java:367)
at org.nustaq.serialization.FSTClazzInfo.<init>(FSTClazzInfo.java:128)
at org.nustaq.serialization.FSTClazzInfoRegistry.getCLInfo(FSTClazzInfoRegistry.java:129)
at org.nustaq.serialization.FSTClazzNameRegistry.addClassMapping(FSTClazzNameRegistry.java:97)
at org.nustaq.serialization.FSTClazzNameRegistry.registerClassNoLookup(FSTClazzNameRegistry.java:84)
at org.nustaq.serialization.FSTClazzNameRegistry.registerClass(FSTClazzNameRegistry.java:80)
at org.nustaq.serialization.FSTConfiguration.addDefaultClazzes(FSTConfiguration.java:811)
at org.nustaq.serialization.FSTConfiguration.initDefaultFstConfigurationInternal(FSTConfiguration.java:478)
at org.nustaq.serialization.FSTConfiguration.createDefaultConfiguration(FSTConfiguration.java:473)
at org.nustaq.serialization.FSTConfiguration.createDefaultConfiguration(FSTConfiguration.java:465)
at org.redisson.codec.FstCodec.<init>(FstCodec.java:47)
at org.redisson.config.Config.<init>(Config.java:104)
at org.redisson.Redisson.<init>(Redisson.java:119)
at org.redisson.Redisson.create(Redisson.java:164)
at org.redisson.jcache.JCacheManager.createCache(JCacheManager.java:125)
at io.pacaso.insights.api.config.Bucket4JConfig.proxyManager(Bucket4JConfig.java:50)
任何帮助将不胜感激。谢谢!
每@tangy(来自评论):
该问题与您的 java 环境无法访问有关 由于 JDK17 中的更新而指定的模块。你需要添加 --add-opens=java.base/java.lang=ALL-UNNAMED 根据您的具体设置添加到您的环境参数中。