From a5c79f2265b1e01bea6dbaa6f69f20948d114f85 Mon Sep 17 00:00:00 2001 From: MarcGiffing Date: Sun, 25 Feb 2024 15:54:05 +0100 Subject: [PATCH] refactors cache resolver (#237) --- .../cache/AbstractCacheResolverTemplate.java | 41 +++++++++++++++++++ .../hazelcast/HazelcastCacheResolver.java | 37 ++++++++--------- .../cache/ignite/IgniteCacheResolver.java | 30 +++++++------- .../infinispan/InfinispanCacheResolver.java | 28 +++++++------ .../cache/jcache/JCacheCacheResolver.java | 31 +++++++------- .../cache/redis/jedis/JedisCacheResolver.java | 35 ++++++++-------- .../redis/lettuce/LettuceCacheResolver.java | 36 ++++++++-------- .../redis/redisson/RedissonCacheResolver.java | 28 +++++++------ 8 files changed, 157 insertions(+), 109 deletions(-) create mode 100644 bucket4j-spring-boot-starter/src/main/java/com/giffing/bucket4j/spring/boot/starter/config/cache/AbstractCacheResolverTemplate.java diff --git a/bucket4j-spring-boot-starter/src/main/java/com/giffing/bucket4j/spring/boot/starter/config/cache/AbstractCacheResolverTemplate.java b/bucket4j-spring-boot-starter/src/main/java/com/giffing/bucket4j/spring/boot/starter/config/cache/AbstractCacheResolverTemplate.java new file mode 100644 index 00000000..175bfb78 --- /dev/null +++ b/bucket4j-spring-boot-starter/src/main/java/com/giffing/bucket4j/spring/boot/starter/config/cache/AbstractCacheResolverTemplate.java @@ -0,0 +1,41 @@ +package com.giffing.bucket4j.spring.boot.starter.config.cache; + +import com.giffing.bucket4j.spring.boot.starter.context.ConsumptionProbeHolder; +import io.github.bucket4j.Bucket; +import io.github.bucket4j.distributed.AsyncBucketProxy; +import io.github.bucket4j.distributed.proxy.AbstractProxyManager; + +import java.util.concurrent.CompletableFuture; + +public abstract class AbstractCacheResolverTemplate { + + public ProxyManagerWrapper resolve(String cacheName) { + AbstractProxyManager proxyManager = getProxyManager(cacheName); + return ((key, numTokens, bucketConfiguration, metricsListener, version, replaceStrategy) -> { + if(isAsync()) { + AsyncBucketProxy bucket = proxyManager.asAsync() + .builder() + .withImplicitConfigurationReplacement(version, replaceStrategy) + .build(castStringToCacheKey(key), () -> CompletableFuture.completedFuture(bucketConfiguration)) + .toListenable(metricsListener); + return new ConsumptionProbeHolder(bucket.tryConsumeAndReturnRemaining(numTokens)); + } else { + Bucket bucket = proxyManager + .builder() + .withImplicitConfigurationReplacement(version, replaceStrategy) + .build(castStringToCacheKey(key), () -> bucketConfiguration) + .toListenable(metricsListener); + return new ConsumptionProbeHolder(bucket.tryConsumeAndReturnRemaining(numTokens)); + } + }); + } + + public abstract T castStringToCacheKey(String key); + + public abstract boolean isAsync(); + + public abstract AbstractProxyManager getProxyManager(String cacheName); + + + +} diff --git a/bucket4j-spring-boot-starter/src/main/java/com/giffing/bucket4j/spring/boot/starter/config/cache/hazelcast/HazelcastCacheResolver.java b/bucket4j-spring-boot-starter/src/main/java/com/giffing/bucket4j/spring/boot/starter/config/cache/hazelcast/HazelcastCacheResolver.java index f3ef96a5..f3dc6c6e 100644 --- a/bucket4j-spring-boot-starter/src/main/java/com/giffing/bucket4j/spring/boot/starter/config/cache/hazelcast/HazelcastCacheResolver.java +++ b/bucket4j-spring-boot-starter/src/main/java/com/giffing/bucket4j/spring/boot/starter/config/cache/hazelcast/HazelcastCacheResolver.java @@ -1,13 +1,11 @@ package com.giffing.bucket4j.spring.boot.starter.config.cache.hazelcast; +import com.giffing.bucket4j.spring.boot.starter.config.cache.AbstractCacheResolverTemplate; import com.giffing.bucket4j.spring.boot.starter.config.cache.AsyncCacheResolver; -import com.giffing.bucket4j.spring.boot.starter.config.cache.ProxyManagerWrapper; -import com.giffing.bucket4j.spring.boot.starter.context.ConsumptionProbeHolder; import com.hazelcast.core.HazelcastInstance; import com.hazelcast.map.IMap; -import io.github.bucket4j.Bucket; -import io.github.bucket4j.distributed.AsyncBucketProxy; +import io.github.bucket4j.distributed.proxy.AbstractProxyManager; import io.github.bucket4j.distributed.proxy.ProxyManager; import io.github.bucket4j.grid.hazelcast.HazelcastProxyManager; @@ -16,7 +14,7 @@ * It uses the {@link HazelcastInstance} to retrieve the needed cache. * */ -public class HazelcastCacheResolver implements AsyncCacheResolver { +public class HazelcastCacheResolver extends AbstractCacheResolverTemplate implements AsyncCacheResolver { private final HazelcastInstance hazelcastInstance; @@ -26,23 +24,20 @@ public HazelcastCacheResolver(HazelcastInstance hazelcastInstance, boolean async this.hazelcastInstance = hazelcastInstance; this.async = async; } - + + @Override + public String castStringToCacheKey(String key) { + return key; + } + + @Override + public boolean isAsync() { + return async; + } + @Override - public ProxyManagerWrapper resolve(String cacheName) { + public AbstractProxyManager getProxyManager(String cacheName) { IMap map = hazelcastInstance.getMap(cacheName); - HazelcastProxyManager hazelcastProxyManager = new HazelcastProxyManager<>(map); - return (key, numTokens, bucketConfiguration, metricsListener, version, replaceStrategy) -> { - if(async) { - AsyncBucketProxy bucket = hazelcastProxyManager.asAsync().builder() - .withImplicitConfigurationReplacement(version, replaceStrategy) - .build(key, bucketConfiguration).toListenable(metricsListener); - return new ConsumptionProbeHolder(bucket.tryConsumeAndReturnRemaining(numTokens)); - } else { - Bucket bucket = hazelcastProxyManager.builder() - .withImplicitConfigurationReplacement(version, replaceStrategy) - .build(key, bucketConfiguration).toListenable(metricsListener); - return new ConsumptionProbeHolder(bucket.tryConsumeAndReturnRemaining(numTokens)); - } - }; + return new HazelcastProxyManager<>(map); } } diff --git a/bucket4j-spring-boot-starter/src/main/java/com/giffing/bucket4j/spring/boot/starter/config/cache/ignite/IgniteCacheResolver.java b/bucket4j-spring-boot-starter/src/main/java/com/giffing/bucket4j/spring/boot/starter/config/cache/ignite/IgniteCacheResolver.java index c2cbc507..6eeb4947 100644 --- a/bucket4j-spring-boot-starter/src/main/java/com/giffing/bucket4j/spring/boot/starter/config/cache/ignite/IgniteCacheResolver.java +++ b/bucket4j-spring-boot-starter/src/main/java/com/giffing/bucket4j/spring/boot/starter/config/cache/ignite/IgniteCacheResolver.java @@ -1,30 +1,32 @@ package com.giffing.bucket4j.spring.boot.starter.config.cache.ignite; +import com.giffing.bucket4j.spring.boot.starter.config.cache.AbstractCacheResolverTemplate; import com.giffing.bucket4j.spring.boot.starter.config.cache.AsyncCacheResolver; -import com.giffing.bucket4j.spring.boot.starter.config.cache.ProxyManagerWrapper; -import com.giffing.bucket4j.spring.boot.starter.context.ConsumptionProbeHolder; - -import io.github.bucket4j.distributed.AsyncBucketProxy; +import io.github.bucket4j.distributed.proxy.AbstractProxyManager; import io.github.bucket4j.grid.ignite.thick.IgniteProxyManager; import org.apache.ignite.Ignite; -public class IgniteCacheResolver implements AsyncCacheResolver { +public class IgniteCacheResolver extends AbstractCacheResolverTemplate implements AsyncCacheResolver { private final Ignite ignite; public IgniteCacheResolver(Ignite ignite) { this.ignite = ignite; } - + + @Override + public String castStringToCacheKey(String key) { + return key; + } + + @Override + public boolean isAsync() { + return false; + } + @Override - public ProxyManagerWrapper resolve(String cacheName) { + public AbstractProxyManager getProxyManager(String cacheName) { org.apache.ignite.IgniteCache cache = ignite.cache(cacheName); - IgniteProxyManager igniteProxyManager = new IgniteProxyManager<>(cache); - return (key, numTokens, bucketConfiguration, metricsListener, version, replaceStrategy) -> { - AsyncBucketProxy bucket = igniteProxyManager.asAsync().builder() - .withImplicitConfigurationReplacement(version, replaceStrategy) - .build(key, bucketConfiguration).toListenable(metricsListener); - return new ConsumptionProbeHolder(bucket.tryConsumeAndReturnRemaining(numTokens)); - }; + return new IgniteProxyManager<>(cache); } } diff --git a/bucket4j-spring-boot-starter/src/main/java/com/giffing/bucket4j/spring/boot/starter/config/cache/infinispan/InfinispanCacheResolver.java b/bucket4j-spring-boot-starter/src/main/java/com/giffing/bucket4j/spring/boot/starter/config/cache/infinispan/InfinispanCacheResolver.java index fa0102f2..e9f0daa8 100644 --- a/bucket4j-spring-boot-starter/src/main/java/com/giffing/bucket4j/spring/boot/starter/config/cache/infinispan/InfinispanCacheResolver.java +++ b/bucket4j-spring-boot-starter/src/main/java/com/giffing/bucket4j/spring/boot/starter/config/cache/infinispan/InfinispanCacheResolver.java @@ -1,9 +1,8 @@ package com.giffing.bucket4j.spring.boot.starter.config.cache.infinispan; +import com.giffing.bucket4j.spring.boot.starter.config.cache.AbstractCacheResolverTemplate; import com.giffing.bucket4j.spring.boot.starter.config.cache.AsyncCacheResolver; -import com.giffing.bucket4j.spring.boot.starter.config.cache.ProxyManagerWrapper; -import com.giffing.bucket4j.spring.boot.starter.context.ConsumptionProbeHolder; -import io.github.bucket4j.distributed.AsyncBucketProxy; +import io.github.bucket4j.distributed.proxy.AbstractProxyManager; import io.github.bucket4j.grid.infinispan.InfinispanProxyManager; import org.infinispan.AdvancedCache; import org.infinispan.Cache; @@ -12,7 +11,7 @@ import org.infinispan.functional.impl.ReadWriteMapImpl; import org.infinispan.manager.CacheContainer; -public class InfinispanCacheResolver implements AsyncCacheResolver { +public class InfinispanCacheResolver extends AbstractCacheResolverTemplate implements AsyncCacheResolver { private final CacheContainer cacheContainer; @@ -21,16 +20,21 @@ public InfinispanCacheResolver(CacheContainer cacheContainer) { } @Override - public ProxyManagerWrapper resolve(String cacheName) { + public String castStringToCacheKey(String key) { + return key; + } + + @Override + public boolean isAsync() { + return true; + } + + @Override + public AbstractProxyManager getProxyManager(String cacheName) { Cache cache = cacheContainer.getCache(cacheName); - InfinispanProxyManager infinispanProxyManager = new InfinispanProxyManager<>(toMap(cache)); - return (key, numTokens, bucketConfiguration, metricsListener, version, replaceStrategy) -> { - AsyncBucketProxy bucket = infinispanProxyManager.asAsync().builder() - .withImplicitConfigurationReplacement(version, replaceStrategy) - .build(key, bucketConfiguration).toListenable(metricsListener); - return new ConsumptionProbeHolder(bucket.tryConsumeAndReturnRemaining(numTokens)); - }; + return new InfinispanProxyManager<>(toMap(cache)); } + private static FunctionalMap.ReadWriteMap toMap(Cache cache) { AdvancedCache advancedCache = cache.getAdvancedCache(); FunctionalMapImpl functionalMap = FunctionalMapImpl.create(advancedCache); diff --git a/bucket4j-spring-boot-starter/src/main/java/com/giffing/bucket4j/spring/boot/starter/config/cache/jcache/JCacheCacheResolver.java b/bucket4j-spring-boot-starter/src/main/java/com/giffing/bucket4j/spring/boot/starter/config/cache/jcache/JCacheCacheResolver.java index 7e5a2b68..6f08b0be 100644 --- a/bucket4j-spring-boot-starter/src/main/java/com/giffing/bucket4j/spring/boot/starter/config/cache/jcache/JCacheCacheResolver.java +++ b/bucket4j-spring-boot-starter/src/main/java/com/giffing/bucket4j/spring/boot/starter/config/cache/jcache/JCacheCacheResolver.java @@ -1,11 +1,10 @@ package com.giffing.bucket4j.spring.boot.starter.config.cache.jcache; +import com.giffing.bucket4j.spring.boot.starter.config.cache.AbstractCacheResolverTemplate; import com.giffing.bucket4j.spring.boot.starter.config.cache.CacheResolver; -import com.giffing.bucket4j.spring.boot.starter.config.cache.ProxyManagerWrapper; import com.giffing.bucket4j.spring.boot.starter.config.cache.SyncCacheResolver; -import com.giffing.bucket4j.spring.boot.starter.context.ConsumptionProbeHolder; import com.giffing.bucket4j.spring.boot.starter.exception.JCacheNotFoundException; -import io.github.bucket4j.Bucket; +import io.github.bucket4j.distributed.proxy.AbstractProxyManager; import io.github.bucket4j.distributed.proxy.ProxyManager; import io.github.bucket4j.grid.jcache.JCacheProxyManager; @@ -17,26 +16,30 @@ * It uses Bucket4Js {@link JCacheProxyManager} to implement the {@link ProxyManager}. * */ -public class JCacheCacheResolver implements SyncCacheResolver { +public class JCacheCacheResolver extends AbstractCacheResolverTemplate implements SyncCacheResolver { private final CacheManager cacheManager; public JCacheCacheResolver(CacheManager cacheManager) { this.cacheManager = cacheManager; } - - public ProxyManagerWrapper resolve(String cacheName) { + + @Override + public String castStringToCacheKey(String key) { + return key; + } + + @Override + public boolean isAsync() { + return false; + } + + @Override + public AbstractProxyManager getProxyManager(String cacheName) { Cache springCache = cacheManager.getCache(cacheName); if (springCache == null) { throw new JCacheNotFoundException(cacheName); } - - JCacheProxyManager jCacheProxyManager = new JCacheProxyManager<>(springCache); - return (key, numTokens, bucketConfiguration, metricsListener, version, replaceStrategy) -> { - Bucket bucket = jCacheProxyManager.builder() - .withImplicitConfigurationReplacement(version, replaceStrategy) - .build(key, bucketConfiguration).toListenable(metricsListener); - return new ConsumptionProbeHolder(bucket.tryConsumeAndReturnRemaining(numTokens)); - }; + return new JCacheProxyManager<>(springCache); } } diff --git a/bucket4j-spring-boot-starter/src/main/java/com/giffing/bucket4j/spring/boot/starter/config/cache/redis/jedis/JedisCacheResolver.java b/bucket4j-spring-boot-starter/src/main/java/com/giffing/bucket4j/spring/boot/starter/config/cache/redis/jedis/JedisCacheResolver.java index 000ee116..25cabc71 100644 --- a/bucket4j-spring-boot-starter/src/main/java/com/giffing/bucket4j/spring/boot/starter/config/cache/redis/jedis/JedisCacheResolver.java +++ b/bucket4j-spring-boot-starter/src/main/java/com/giffing/bucket4j/spring/boot/starter/config/cache/redis/jedis/JedisCacheResolver.java @@ -1,23 +1,22 @@ package com.giffing.bucket4j.spring.boot.starter.config.cache.redis.jedis; +import com.giffing.bucket4j.spring.boot.starter.config.cache.AbstractCacheResolverTemplate; import com.giffing.bucket4j.spring.boot.starter.config.cache.CacheResolver; -import com.giffing.bucket4j.spring.boot.starter.config.cache.ProxyManagerWrapper; import com.giffing.bucket4j.spring.boot.starter.config.cache.SyncCacheResolver; -import com.giffing.bucket4j.spring.boot.starter.context.ConsumptionProbeHolder; -import io.github.bucket4j.Bucket; import io.github.bucket4j.distributed.ExpirationAfterWriteStrategy; -import io.github.bucket4j.distributed.proxy.ProxyManager; +import io.github.bucket4j.distributed.proxy.AbstractProxyManager; import io.github.bucket4j.redis.jedis.cas.JedisBasedProxyManager; -import static java.nio.charset.StandardCharsets.UTF_8; import redis.clients.jedis.JedisPool; import java.time.Duration; +import static java.nio.charset.StandardCharsets.UTF_8; + /** * This class is the Redis implementation of the {@link CacheResolver}. * */ -public class JedisCacheResolver implements SyncCacheResolver { +public class JedisCacheResolver extends AbstractCacheResolverTemplate implements SyncCacheResolver { private final JedisPool pool; @@ -25,18 +24,20 @@ public JedisCacheResolver(JedisPool pool) { this.pool = pool; } - @Override - public ProxyManagerWrapper resolve(String cacheName) { - final ProxyManager proxyManager = JedisBasedProxyManager.builderFor(pool) + @Override + public boolean isAsync() { + return false; + } + + @Override + public byte[] castStringToCacheKey(String key) { + return key.getBytes(UTF_8); + } + + @Override + public AbstractProxyManager getProxyManager(String cacheName) { + return JedisBasedProxyManager.builderFor(pool) .withExpirationStrategy(ExpirationAfterWriteStrategy.basedOnTimeForRefillingBucketUpToMax(Duration.ofSeconds(10))) .build(); - - return (key, numTokens, bucketConfiguration, metricsListener, version, replaceStrategy) -> { - Bucket bucket = proxyManager.builder() - .withImplicitConfigurationReplacement(version, replaceStrategy) - .build(key.getBytes(UTF_8), bucketConfiguration).toListenable(metricsListener); - return new ConsumptionProbeHolder(bucket.tryConsumeAndReturnRemaining(numTokens)); - }; - } } diff --git a/bucket4j-spring-boot-starter/src/main/java/com/giffing/bucket4j/spring/boot/starter/config/cache/redis/lettuce/LettuceCacheResolver.java b/bucket4j-spring-boot-starter/src/main/java/com/giffing/bucket4j/spring/boot/starter/config/cache/redis/lettuce/LettuceCacheResolver.java index 37728b17..58738ed3 100644 --- a/bucket4j-spring-boot-starter/src/main/java/com/giffing/bucket4j/spring/boot/starter/config/cache/redis/lettuce/LettuceCacheResolver.java +++ b/bucket4j-spring-boot-starter/src/main/java/com/giffing/bucket4j/spring/boot/starter/config/cache/redis/lettuce/LettuceCacheResolver.java @@ -1,24 +1,21 @@ package com.giffing.bucket4j.spring.boot.starter.config.cache.redis.lettuce; -import static java.nio.charset.StandardCharsets.UTF_8; - -import java.time.Duration; - +import com.giffing.bucket4j.spring.boot.starter.config.cache.AbstractCacheResolverTemplate; import com.giffing.bucket4j.spring.boot.starter.config.cache.AsyncCacheResolver; import com.giffing.bucket4j.spring.boot.starter.config.cache.CacheResolver; -import com.giffing.bucket4j.spring.boot.starter.config.cache.ProxyManagerWrapper; -import com.giffing.bucket4j.spring.boot.starter.context.ConsumptionProbeHolder; - -import io.github.bucket4j.distributed.AsyncBucketProxy; import io.github.bucket4j.distributed.ExpirationAfterWriteStrategy; -import io.github.bucket4j.distributed.proxy.ProxyManager; +import io.github.bucket4j.distributed.proxy.AbstractProxyManager; import io.github.bucket4j.redis.lettuce.cas.LettuceBasedProxyManager; import io.lettuce.core.RedisClient; +import java.time.Duration; + +import static java.nio.charset.StandardCharsets.UTF_8; + /** * This class is the Redis implementation of the {@link CacheResolver}. */ -public class LettuceCacheResolver implements AsyncCacheResolver { +public class LettuceCacheResolver extends AbstractCacheResolverTemplate implements AsyncCacheResolver { private final RedisClient redisClient; @@ -27,16 +24,19 @@ public LettuceCacheResolver(RedisClient redisClient) { } @Override - public ProxyManagerWrapper resolve(String cacheName) { - final ProxyManager proxyManager = LettuceBasedProxyManager.builderFor(redisClient) + public boolean isAsync() { + return true; + } + + @Override + public AbstractProxyManager getProxyManager(String cacheName) { + return LettuceBasedProxyManager.builderFor(redisClient) .withExpirationStrategy(ExpirationAfterWriteStrategy.basedOnTimeForRefillingBucketUpToMax(Duration.ofSeconds(10))) .build(); + } - return (key, numTokens, bucketConfiguration, metricsListener, version, replaceStrategy) -> { - AsyncBucketProxy bucket = proxyManager.asAsync().builder() - .withImplicitConfigurationReplacement(version, replaceStrategy) - .build(key.getBytes(UTF_8), bucketConfiguration).toListenable(metricsListener); - return new ConsumptionProbeHolder(bucket.tryConsumeAndReturnRemaining(numTokens)); - }; + @Override + public byte[] castStringToCacheKey(String key) { + return key.getBytes(UTF_8); } } diff --git a/bucket4j-spring-boot-starter/src/main/java/com/giffing/bucket4j/spring/boot/starter/config/cache/redis/redisson/RedissonCacheResolver.java b/bucket4j-spring-boot-starter/src/main/java/com/giffing/bucket4j/spring/boot/starter/config/cache/redis/redisson/RedissonCacheResolver.java index 96d6789d..19b44987 100644 --- a/bucket4j-spring-boot-starter/src/main/java/com/giffing/bucket4j/spring/boot/starter/config/cache/redis/redisson/RedissonCacheResolver.java +++ b/bucket4j-spring-boot-starter/src/main/java/com/giffing/bucket4j/spring/boot/starter/config/cache/redis/redisson/RedissonCacheResolver.java @@ -1,11 +1,10 @@ package com.giffing.bucket4j.spring.boot.starter.config.cache.redis.redisson; +import com.giffing.bucket4j.spring.boot.starter.config.cache.AbstractCacheResolverTemplate; import com.giffing.bucket4j.spring.boot.starter.config.cache.AsyncCacheResolver; import com.giffing.bucket4j.spring.boot.starter.config.cache.CacheResolver; -import com.giffing.bucket4j.spring.boot.starter.config.cache.ProxyManagerWrapper; -import com.giffing.bucket4j.spring.boot.starter.context.ConsumptionProbeHolder; -import io.github.bucket4j.distributed.AsyncBucketProxy; import io.github.bucket4j.distributed.ExpirationAfterWriteStrategy; +import io.github.bucket4j.distributed.proxy.AbstractProxyManager; import io.github.bucket4j.redis.redisson.cas.RedissonBasedProxyManager; import org.redisson.command.CommandAsyncExecutor; @@ -14,7 +13,7 @@ /** * This class is the Redis implementation of the {@link CacheResolver}. */ -public class RedissonCacheResolver implements AsyncCacheResolver { +public class RedissonCacheResolver extends AbstractCacheResolverTemplate implements AsyncCacheResolver { private final CommandAsyncExecutor commandExecutor; @@ -23,16 +22,19 @@ public RedissonCacheResolver(CommandAsyncExecutor commandExecutor) { } @Override - public ProxyManagerWrapper resolve(String cacheName) { - var proxyManager = RedissonBasedProxyManager.builderFor(commandExecutor) + public String castStringToCacheKey(String key) { + return key; + } + + @Override + public boolean isAsync() { + return true; + } + + @Override + public AbstractProxyManager getProxyManager(String cacheName) { + return RedissonBasedProxyManager.builderFor(commandExecutor) .withExpirationStrategy(ExpirationAfterWriteStrategy.basedOnTimeForRefillingBucketUpToMax(Duration.ofSeconds(10))) .build(); - - return (key, numTokens, bucketConfiguration, metricsListener, version, replaceStrategy) -> { - AsyncBucketProxy bucket = proxyManager.asAsync().builder() - .withImplicitConfigurationReplacement(version, replaceStrategy) - .build(key, bucketConfiguration).toListenable(metricsListener); - return new ConsumptionProbeHolder(bucket.tryConsumeAndReturnRemaining(numTokens)); - }; } }