diff --git a/src/main/java/org/redkale/cache/Cached.java b/src/main/java/org/redkale/cache/Cached.java index f4f5f8d20..d82bf1696 100644 --- a/src/main/java/org/redkale/cache/Cached.java +++ b/src/main/java/org/redkale/cache/Cached.java @@ -40,7 +40,7 @@ public @interface Cached { * * @return hash */ - String map() default ""; + String hash() default ""; /** * 本地缓存过期时长, 0表示永不过期, -1表示不作本地缓存。
diff --git a/src/main/java/org/redkale/cache/spi/CacheAction.java b/src/main/java/org/redkale/cache/spi/CacheAction.java index 341c8e140..9e340d4f1 100644 --- a/src/main/java/org/redkale/cache/spi/CacheAction.java +++ b/src/main/java/org/redkale/cache/spi/CacheAction.java @@ -6,14 +6,18 @@ package org.redkale.cache.spi; import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; import java.time.Duration; +import java.util.Objects; import java.util.concurrent.CompletableFuture; import java.util.function.Supplier; +import org.redkale.annotation.Nullable; import org.redkale.annotation.Resource; import org.redkale.cache.CacheManager; import org.redkale.cache.Cached; import org.redkale.convert.json.JsonConvert; +import org.redkale.net.sncp.Sncp; import org.redkale.util.Environment; import org.redkale.util.TypeToken; +import org.redkale.util.CombinedKey; /** * @@ -45,10 +49,18 @@ public class CacheAction { //是否可以缓存null private final boolean nullable; + //宿主对象的类 + private final Class serviceClass; + //无法获取动态的Method,只能存方法名 private final String methodName; + //方法参数类型 + @Nullable + private final Class[] paramTypes; + //方法参数名 + @Nullable private final String[] paramNames; //缓存的hash @@ -57,24 +69,32 @@ public class CacheAction { //缓存的key private String key; + //缓存的key + private CombinedKey dynKey; + //本地缓存过期时长 private Duration localExpire; //远程缓存过期时长 private Duration remoteExpire; - CacheAction(Cached cached, Type returnType, String[] paramNames, String methodName) { + CacheAction(Cached cached, Type returnType, Class serviceClass, Class[] paramTypes, String[] paramNames, String methodName) { this.cached = cached; this.nullable = cached.nullable(); + this.serviceClass = Objects.requireNonNull(serviceClass); + this.paramTypes = paramTypes; this.paramNames = paramNames; - this.methodName = methodName; + this.methodName = Objects.requireNonNull(methodName); this.async = CompletableFuture.class.isAssignableFrom(TypeToken.typeToClass(returnType)); this.resultType = this.async ? ((ParameterizedType) returnType).getActualTypeArguments()[0] : returnType; } void init() { - this.hash = environment.getPropertyValue(cached.map()); + this.hash = cached.hash().trim().isEmpty() + ? Sncp.getResourceType(serviceClass).getSimpleName() + : environment.getPropertyValue(cached.hash()); this.key = environment.getPropertyValue(cached.key()); + this.dynKey = CombinedKey.create(paramTypes, paramNames, key); this.localExpire = createDuration(cached.localExpire()); this.remoteExpire = createDuration(cached.remoteExpire()); } @@ -82,16 +102,12 @@ public class CacheAction { public T get(Supplier supplier, Object... args) { if (async) { Supplier supplier0 = supplier; - return (T) manager.bothGetAsync(hash, keyFor(args), resultType, nullable, localExpire, remoteExpire, supplier0); + return (T) manager.bothGetAsync(hash, dynKey.keyFor(args), resultType, nullable, localExpire, remoteExpire, supplier0); } else { - return manager.bothGet(hash, keyFor(args), resultType, nullable, localExpire, remoteExpire, supplier); + return manager.bothGet(hash, dynKey.keyFor(args), resultType, nullable, localExpire, remoteExpire, supplier); } } - private String keyFor(Object... args) { - return ""; - } - private Duration createDuration(String val) { String str = environment.getPropertyValue(val); if ("-1".equals(str) || "null".equalsIgnoreCase(str)) { @@ -103,12 +119,20 @@ public class CacheAction { } } + @Override public String toString() { - return JsonConvert.root().convertTo(this); - } - - class CacheKey { - private String key; - + return "{" + + "\"serviceClass\":" + serviceClass.getName() + + ",\"methodName\":\"" + methodName + "\"" + + ",\"paramTypes\":" + JsonConvert.root().convertTo(paramTypes) + + ",\"paramNames\":" + JsonConvert.root().convertTo(paramNames) + + ",\"hash\":\"" + cached.hash() + "\"" + + ",\"key\":" + JsonConvert.root().convertTo(key) + + ",\"localExpire\":\"" + cached.localExpire() + "\"" + + ",\"remoteExpire\":\"" + cached.remoteExpire() + "\"" + + ",\"timeUnit\":\"" + cached.timeUnit() + "\"" + + ",\"nullable\":" + cached.nullable() + + "}"; } + } diff --git a/src/main/java/org/redkale/cache/spi/DynForCache.java b/src/main/java/org/redkale/cache/spi/DynForCache.java index 1f5f9bf34..305a17fbb 100644 --- a/src/main/java/org/redkale/cache/spi/DynForCache.java +++ b/src/main/java/org/redkale/cache/spi/DynForCache.java @@ -29,7 +29,7 @@ public @interface DynForCache { String key(); - String map(); + String hash(); String localExpire(); diff --git a/src/main/java/org/redkale/util/CombinedKey.java b/src/main/java/org/redkale/util/CombinedKey.java new file mode 100644 index 000000000..f9b612764 --- /dev/null +++ b/src/main/java/org/redkale/util/CombinedKey.java @@ -0,0 +1,33 @@ +/* + * + */ +package org.redkale.util; + +/** + * 根据参数动态生成key + * + *

+ * 详情见: https://redkale.org + * + * + * @author zhangjx + * + * @since 2.8.0 + */ +public interface CombinedKey { + + public String keyFor(Object... args); + + /** + * 生成Key, paramTypes与paramNames长度必须一致 + * + * @param paramTypes 参数类型 + * @param paramNames 参数名 + * @param key key表达式 + * + * @return CombinedKey + */ + public static CombinedKey create(Class[] paramTypes, String[] paramNames, String key) { + return CombinedKeys.create(paramTypes, paramNames, key); + } +} diff --git a/src/main/java/org/redkale/util/CombinedKeys.java b/src/main/java/org/redkale/util/CombinedKeys.java new file mode 100644 index 000000000..337b2be13 --- /dev/null +++ b/src/main/java/org/redkale/util/CombinedKeys.java @@ -0,0 +1,87 @@ +/* + * + */ +package org.redkale.util; + +import java.util.Objects; + +/** + * + * @author zhangjx + */ +class CombinedKeys { + + public static CombinedKey create(Class[] paramTypes, String[] paramNames, String key) { + Objects.requireNonNull(key, "key for " + CombinedKey.class.getSimpleName() + " is null"); + if ((paramTypes != null && paramNames != null && paramTypes.length != paramNames.length) + || (paramTypes == null && paramNames != null) + || (paramTypes != null && paramNames == null)) { + throw new IllegalArgumentException("paramTypes.length and paramNames.length is inconsistent"); + } + if (key.indexOf('{') < 0) { + return new StringDynamicKey(key); + } else { + if (paramNames != null) { + for (int i = 0; i < paramNames.length; i++) { + if (key.equalsIgnoreCase("#{" + paramNames[i] + "}")) { + return new ParamDynamicKey(i); + } + } + } + return new CombinedDynamicKey(paramTypes, paramNames, key); + } + } + + static class CombinedDynamicKey implements CombinedKey { + + private final CombinedKey[] keys; + + public CombinedDynamicKey(Class[] paramTypes, String[] paramNames, String key) { + this.keys = new CombinedKey[0]; + } + + @Override + public String keyFor(Object... args) { + StringBuilder sb = new StringBuilder(); + for (CombinedKey key : keys) { + sb.append(key.keyFor(args)); + } + return sb.toString(); + } + + } + + static class ParamDynamicKey implements CombinedKey { + + private final int index; + + public ParamDynamicKey(int index) { + this.index = index; + } + + @Override + public String keyFor(Object... args) { + return String.valueOf(args[index]); + } + + } + + static class StringDynamicKey implements CombinedKey { + + private final String key; + + public StringDynamicKey(String key) { + this.key = key; + } + + @Override + public String keyFor(Object... args) { + return key; + } + } + + private CombinedKeys() { + //do nothing + } + +}