diff --git a/src/main/java/module-info.java b/src/main/java/module-info.java index 34d83360b..01dae9a8a 100644 --- a/src/main/java/module-info.java +++ b/src/main/java/module-info.java @@ -25,7 +25,7 @@ module org.redkale { exports org.redkale.convert.ext; exports org.redkale.convert.json; exports org.redkale.convert.protobuf; - exports org.redkale.locking; + exports org.redkale.lock; exports org.redkale.mq; exports org.redkale.net; exports org.redkale.net.client; diff --git a/src/main/java/org/redkale/cache/CacheManager.java b/src/main/java/org/redkale/cache/CacheManager.java index c4418c0b9..e8f2fd904 100644 --- a/src/main/java/org/redkale/cache/CacheManager.java +++ b/src/main/java/org/redkale/cache/CacheManager.java @@ -6,6 +6,7 @@ package org.redkale.cache; import java.lang.reflect.Type; import java.time.Duration; import java.util.concurrent.CompletableFuture; +import java.util.function.Supplier; /** * 缓存管理器 @@ -24,296 +25,324 @@ public interface CacheManager { * 本地获取缓存数据, 过期返回null * * @param 泛型 - * @param map 缓存hash + * @param hash 缓存hash * @param key 缓存键 * @param type 数据类型 * * @return 数据值 */ - public T localGet(final String map, final String key, final Type type); + public T localGet(final String hash, final String key, final Type type); /** * 本地获取字符串缓存数据, 过期返回null * - * @param map 缓存hash - * @param key 缓存键 + * @param hash 缓存hash + * @param key 缓存键 * * @return 数据值 */ - default String localGetString(final String map, final String key) { - return localGet(map, key, String.class); + default String localGetString(final String hash, final String key) { + return localGet(hash, key, String.class); } + /** + * 本地获取缓存数据, 过期返回null + * + * @param 泛型 + * @param hash 缓存hash + * @param key 缓存键 + * @param type 数据类型 + * @param expire 过期时长,为null表示永不过期 + * @param supplier 数据函数 + * + * @return 数据值 + */ + public T localGet(final String hash, final String key, final Type type, Duration expire, Supplier supplier); + + /** + * 远程异步获取缓存数据, 过期返回null + * + * @param 泛型 + * @param hash 缓存hash + * @param key 缓存键 + * @param type 数据类型 + * @param expire 过期时长,为null表示永不过期 + * @param supplier 数据函数 + * + * @return 数据值 + */ + public CompletableFuture localGetAsync(String hash, String key, Type type, Duration expire, Supplier> supplier); + /** * 本地缓存数据 * * @param 泛型 - * @param map 缓存hash + * @param hash 缓存hash * @param key 缓存键 * @param type 数据类型 * @param value 数据值 * @param expire 过期时长,为null表示永不过期 */ - public void localSet(String map, String key, Type type, T value, Duration expire); + public void localSet(String hash, String key, Type type, T value, Duration expire); /** * 本地缓存字符串数据 * - * @param map 缓存hash + * @param hash 缓存hash * @param key 缓存键 * @param value 数据值 * @param expire 过期时长,为null表示永不过期 */ - default void localSetString(final String map, final String key, final String value, Duration expire) { - localSet(map, key, String.class, value, expire); + default void localSetString(final String hash, final String key, final String value, Duration expire) { + localSet(hash, key, String.class, value, expire); } /** * 本地删除缓存数据 * - * @param map 缓存hash - * @param key 缓存键 + * @param hash 缓存hash + * @param key 缓存键 * * @return 删除数量 */ - public long localDel(String map, String key); + public long localDel(String hash, String key); //-------------------------------------- 远程缓存 -------------------------------------- /** * 远程获取缓存数据, 过期返回null * * @param 泛型 - * @param map 缓存hash + * @param hash 缓存hash * @param key 缓存键 * @param type 数据类型 * * @return 数据值 */ - public T remoteGet(final String map, final String key, final Type type); + public T remoteGet(final String hash, final String key, final Type type); /** * 远程获取字符串缓存数据, 过期返回null * - * @param map 缓存hash - * @param key 缓存键 + * @param hash 缓存hash + * @param key 缓存键 * * @return 数据值 */ - default String remoteGetString(final String map, final String key) { - return remoteGet(map, key, String.class); + default String remoteGetString(final String hash, final String key) { + return remoteGet(hash, key, String.class); } /** * 远程异步获取缓存数据, 过期返回null * * @param 泛型 - * @param map 缓存hash + * @param hash 缓存hash * @param key 缓存键 * @param type 数据类型 * * @return 数据值 */ - public CompletableFuture remoteGetAsync(final String map, final String key, final Type type); + public CompletableFuture remoteGetAsync(final String hash, final String key, final Type type); /** * 远程异步获取字符串缓存数据, 过期返回null * - * @param map 缓存hash - * @param key 缓存键 + * @param hash 缓存hash + * @param key 缓存键 * * @return 数据值 */ - default CompletableFuture remoteGetStringAsync(final String map, final String key) { - return remoteGetAsync(map, key, String.class); + default CompletableFuture remoteGetStringAsync(final String hash, final String key) { + return remoteGetAsync(hash, key, String.class); } /** * 远程缓存数据 * * @param 泛型 - * @param map 缓存hash + * @param hash 缓存hash * @param key 缓存键 * @param type 数据类型 * @param value 数据值 * @param expire 过期时长,为null表示永不过期 */ - public void remoteSet(final String map, final String key, final Type type, final T value, Duration expire); + public void remoteSet(final String hash, final String key, final Type type, final T value, Duration expire); /** * 远程缓存字符串数据 * - * @param map 缓存hash + * @param hash 缓存hash * @param key 缓存键 * @param value 数据值 * @param expire 过期时长,为null表示永不过期 */ - default void remoteSetString(final String map, final String key, final String value, Duration expire) { - remoteSet(map, key, String.class, value, expire); + default void remoteSetString(final String hash, final String key, final String value, Duration expire) { + remoteSet(hash, key, String.class, value, expire); } /** * 远程异步缓存数据 * * @param 泛型 - * @param map 缓存hash + * @param hash 缓存hash * @param key 缓存键 * @param type 数据类型 * @param value 数据值 * @param expire 过期时长,为null表示永不过期 */ - public CompletableFuture remoteSetAsync(String map, String key, Type type, T value, Duration expire); + public CompletableFuture remoteSetAsync(String hash, String key, Type type, T value, Duration expire); /** * 远程异步缓存字符串数据 * - * @param map 缓存hash + * @param hash 缓存hash * @param key 缓存键 * @param value 数据值 * @param expire 过期时长,为null表示永不过期 */ - default CompletableFuture remoteSetStringAsync(final String map, final String key, final String value, Duration expire) { - return remoteSetAsync(map, key, String.class, value, expire); + default CompletableFuture remoteSetStringAsync(final String hash, final String key, final String value, Duration expire) { + return remoteSetAsync(hash, key, String.class, value, expire); } /** * 远程删除缓存数据 * - * @param map 缓存hash - * @param key 缓存键 + * @param hash 缓存hash + * @param key 缓存键 * * @return 删除数量 */ - public long remoteDel(String map, String key); + public long remoteDel(String hash, String key); /** * 远程异步删除缓存数据 * - * @param map 缓存hash - * @param key 缓存键 + * @param hash 缓存hash + * @param key 缓存键 * * @return 删除数量 */ - public CompletableFuture remoteDelAsync(String map, String key); + public CompletableFuture remoteDelAsync(String hash, String key); //-------------------------------------- both缓存 -------------------------------------- /** * 远程获取缓存数据, 过期返回null * * @param 泛型 - * @param map 缓存hash + * @param hash 缓存hash * @param key 缓存键 * @param type 数据类型 * * @return 数据值 */ - public T bothGet(final String map, final String key, final Type type); + public T bothGet(final String hash, final String key, final Type type); /** * 远程获取字符串缓存数据, 过期返回null * - * @param map 缓存hash - * @param key 缓存键 + * @param hash 缓存hash + * @param key 缓存键 * * @return 数据值 */ - default String bothGetString(final String map, final String key) { - return bothGet(map, key, String.class); + default String bothGetString(final String hash, final String key) { + return bothGet(hash, key, String.class); } /** * 远程异步获取缓存数据, 过期返回null * * @param 泛型 - * @param map 缓存hash + * @param hash 缓存hash * @param key 缓存键 * @param type 数据类型 * * @return 数据值 */ - public CompletableFuture bothGetAsync(final String map, final String key, final Type type); + public CompletableFuture bothGetAsync(final String hash, final String key, final Type type); /** * 远程异步获取字符串缓存数据, 过期返回null * - * @param map 缓存hash - * @param key 缓存键 + * @param hash 缓存hash + * @param key 缓存键 * * @return 数据值 */ - default CompletableFuture bothGetStringAsync(final String map, final String key) { - return bothGetAsync(map, key, String.class); + default CompletableFuture bothGetStringAsync(final String hash, final String key) { + return bothGetAsync(hash, key, String.class); } /** * 远程缓存数据 * * @param 泛型 - * @param map 缓存hash + * @param hash 缓存hash * @param key 缓存键 * @param type 数据类型 * @param value 数据值 * @param localExpire 本地过期时长,为null表示永不过期 * @param remoteExpire 远程过期时长,为null表示永不过期 */ - public void bothSet(final String map, final String key, final Type type, final T value, Duration localExpire, Duration remoteExpire); + public void bothSet(final String hash, final String key, final Type type, final T value, Duration localExpire, Duration remoteExpire); /** * 远程缓存字符串数据 * - * @param map 缓存hash + * @param hash 缓存hash * @param key 缓存键 * @param value 数据值 * @param localExpire 本地过期时长,为null表示永不过期 * @param remoteExpire 远程过期时长,为null表示永不过期 */ - default void bothSetString(final String map, final String key, final String value, Duration localExpire, Duration remoteExpire) { - bothSet(map, key, String.class, value, localExpire, remoteExpire); + default void bothSetString(final String hash, final String key, final String value, Duration localExpire, Duration remoteExpire) { + bothSet(hash, key, String.class, value, localExpire, remoteExpire); } /** * 远程异步缓存数据 * * @param 泛型 - * @param map 缓存hash + * @param hash 缓存hash * @param key 缓存键 * @param type 数据类型 * @param value 数据值 * @param localExpire 本地过期时长,为null表示永不过期 * @param remoteExpire 远程过期时长,为null表示永不过期 */ - public CompletableFuture bothSetAsync(String map, String key, Type type, T value, Duration localExpire, Duration remoteExpire); + public CompletableFuture bothSetAsync(String hash, String key, Type type, T value, Duration localExpire, Duration remoteExpire); /** * 远程异步缓存字符串数据 * - * @param map 缓存hash + * @param hash 缓存hash * @param key 缓存键 * @param value 数据值 * @param localExpire 本地过期时长,为null表示永不过期 * @param remoteExpire 远程过期时长,为null表示永不过期 */ - default CompletableFuture bothSetStringAsync(String map, String key, String value, Duration localExpire, Duration remoteExpire) { - return bothSetAsync(map, key, String.class, value, localExpire, remoteExpire); + default CompletableFuture bothSetStringAsync(String hash, String key, String value, Duration localExpire, Duration remoteExpire) { + return bothSetAsync(hash, key, String.class, value, localExpire, remoteExpire); } /** * 远程删除缓存数据 * - * @param map 缓存hash - * @param key 缓存键 + * @param hash 缓存hash + * @param key 缓存键 * * @return 删除数量 */ - public long bothDel(String map, String key); + public long bothDel(String hash, String key); /** * 远程异步删除缓存数据 * - * @param map 缓存hash - * @param key 缓存键 + * @param hash 缓存hash + * @param key 缓存键 * * @return 删除数量 */ - public CompletableFuture bothDelAsync(String map, String key); + public CompletableFuture bothDelAsync(String hash, String key); } diff --git a/src/main/java/org/redkale/cache/support/CacheAction.java b/src/main/java/org/redkale/cache/support/CacheAction.java new file mode 100644 index 000000000..6381120f2 --- /dev/null +++ b/src/main/java/org/redkale/cache/support/CacheAction.java @@ -0,0 +1,27 @@ +/* + * + */ +package org.redkale.cache.support; + +import java.lang.reflect.Method; +import org.redkale.convert.json.JsonConvert; + +/** + * + * 缓存的方法对象 + * + *

+ * 详情见: https://redkale.org + * + * @author zhangjx + * + * @since 2.8.0 + */ +public class CacheAction { + + private Method method; + + public String toString() { + return JsonConvert.root().convertTo(this); + } +} diff --git a/src/main/java/org/redkale/cache/support/CacheManagerService.java b/src/main/java/org/redkale/cache/support/CacheManagerService.java index e0346c806..32779da68 100644 --- a/src/main/java/org/redkale/cache/support/CacheManagerService.java +++ b/src/main/java/org/redkale/cache/support/CacheManagerService.java @@ -5,9 +5,11 @@ package org.redkale.cache.support; import java.lang.reflect.Type; import java.time.Duration; +import java.util.Objects; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentSkipListSet; +import java.util.function.Supplier; import org.redkale.annotation.AutoLoad; import org.redkale.annotation.Component; import org.redkale.annotation.Nullable; @@ -35,9 +37,12 @@ import org.redkale.util.Utility; @ResourceType(CacheManager.class) public class CacheManagerService implements CacheManager, Service { - //缓存配置项 + //是否开启缓存 protected boolean enabled = true; + //是否缓存null值 + protected boolean nullable = false; + //配置 protected AnyValue config; @@ -50,6 +55,9 @@ public class CacheManagerService implements CacheManager, Service { //缓存hash集合, 用于定时遍历删除过期数据 protected final ConcurrentSkipListSet hashNames = new ConcurrentSkipListSet<>(); + //缓存无效时使用的锁 + private final ConcurrentHashMap hashLock = new ConcurrentHashMap<>(); + @Resource(required = false) protected Application application; @@ -133,6 +141,56 @@ public class CacheManagerService implements CacheManager, Service { return CacheValue.get(val); } + /** + * 本地获取缓存数据, 过期返回null + * + * @param 泛型 + * @param hash 缓存hash + * @param key 缓存键 + * @param type 数据类型 + * @param expire 过期时长,为null表示永不过期 + * @param supplier 数据函数 + * + * @return 数据值 + */ + public T localGet(final String hash, final String key, final Type type, Duration expire, Supplier supplier) { + Objects.requireNonNull(supplier); + Type t = loadCacheType(type); + CacheValue val = localSource.hget(hash, key, t); + if (CacheValue.isValid(val)) { + return val.getValue(); + } + String lockKey = lockKey(hash, key); + val = hashLock.computeIfAbsent(lockKey, k -> cacheSupplier(expire, supplier).get()); + try { + if (CacheValue.isValid(val)) { + localSource.hset(hash, key, t, val); + return val.getValue(); + } else { + return null; + } + } finally { + hashLock.remove(lockKey); + } + } + + /** + * 远程异步获取缓存数据, 过期返回null + * + * @param 泛型 + * @param hash 缓存hash + * @param key 缓存键 + * @param type 数据类型 + * @param expire 过期时长,为null表示永不过期 + * @param supplier 数据函数 + * + * @return 数据值 + */ + @Override + public CompletableFuture localGetAsync(String hash, String key, Type type, Duration expire, Supplier> supplier) { + throw new UnsupportedOperationException("Not supported yet."); + } + /** * 本地缓存数据 * @@ -377,6 +435,45 @@ public class CacheManagerService implements CacheManager, Service { } //-------------------------------------- 内部方法 -------------------------------------- + /** + * 创建一个锁key + * + * @param hash 缓存hash + * @param key 缓存键 + * + * @return + */ + protected String lockKey(String hash, String key) { + return hash + (char) 8 + key; + } + + /** + * 将原始数据函数转换成获取CacheValue数据函数 + * + * @param expire 过期时长,为null表示永不过期 + * @param supplier 数据函数 + * + * @return CacheValue函数 + */ + protected CacheValue cacheFunc(Duration expire, T value) { + if (value == null) { + return nullable ? CacheValue.create(value, expire) : null; + } + return CacheValue.create(value, expire); + } + + /** + * 将原始数据函数转换成获取CacheValue数据函数 + * + * @param expire 过期时长,为null表示永不过期 + * @param supplier 数据函数 + * + * @return CacheValue函数 + */ + protected Supplier> cacheSupplier(Duration expire, Supplier supplier) { + return () -> cacheFunc(expire, supplier.get()); + } + /** * 创建数据类型创建对应CacheValue泛型 * @@ -399,4 +496,5 @@ public class CacheManagerService implements CacheManager, Service { protected Type loadCacheType(Type type) { return cacheValueTypes.computeIfAbsent(type, t -> TypeToken.createParameterizedType(null, CacheValue.class, type)); } + } diff --git a/src/main/java/org/redkale/locking/Locked.java b/src/main/java/org/redkale/lock/Locked.java similarity index 95% rename from src/main/java/org/redkale/locking/Locked.java rename to src/main/java/org/redkale/lock/Locked.java index d6d9766c0..564c4b578 100644 --- a/src/main/java/org/redkale/locking/Locked.java +++ b/src/main/java/org/redkale/lock/Locked.java @@ -1,7 +1,7 @@ /* * */ -package org.redkale.locking; +package org.redkale.lock; import java.lang.annotation.Documented; import static java.lang.annotation.ElementType.METHOD;