diff --git a/src/main/java/org/redkale/cache/Cached.java b/src/main/java/org/redkale/cache/Cached.java
index ab587a0c3..b799a6661 100644
--- a/src/main/java/org/redkale/cache/Cached.java
+++ b/src/main/java/org/redkale/cache/Cached.java
@@ -3,18 +3,20 @@
*/
package org.redkale.cache;
-import static java.lang.annotation.ElementType.METHOD;
-import static java.lang.annotation.RetentionPolicy.RUNTIME;
-
import java.lang.annotation.Documented;
+import static java.lang.annotation.ElementType.METHOD;
import java.lang.annotation.Retention;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
import java.lang.annotation.Target;
import java.util.concurrent.TimeUnit;
import org.redkale.service.LoadMode;
/**
* 标记在Service的缓存接口, 方法有以下限制:
- * 1、方法返回类型不能是void/CompletableFuture<Void> 2、方法返回类型必须可json序列化 3、方法必须是protected/public 4、方法不能是final/static
+ * 1、方法返回类型不能是void/CompletableFuture<Void>
+ * 2、方法返回类型必须可json序列化
+ * 3、方法必须是protected/public
+ * 4、方法不能是final/static
*
* @since 2.8.0
*/
@@ -24,7 +26,10 @@ import org.redkale.service.LoadMode;
public @interface Cached {
/**
- * 缓存的key,支持参数动态组合,比如"key_#{id}"
+ * 缓存的key,支持参数动态组合,比如"key_#{id}"
+ * '@'开头的key值视为CacheKeyGenerator对象名称
+ *
+ * @see org.redkale.cache.spi.CacheKeyGenerator#name()
*
* @return 键
*/
diff --git a/src/main/java/org/redkale/cache/spi/CacheAction.java b/src/main/java/org/redkale/cache/spi/CacheAction.java
index f936d5db5..e85991ec5 100644
--- a/src/main/java/org/redkale/cache/spi/CacheAction.java
+++ b/src/main/java/org/redkale/cache/spi/CacheAction.java
@@ -3,6 +3,7 @@
*/
package org.redkale.cache.spi;
+import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.time.Duration;
@@ -13,6 +14,7 @@ import org.redkale.annotation.Nullable;
import org.redkale.annotation.Resource;
import org.redkale.cache.CacheManager;
import org.redkale.convert.json.JsonConvert;
+import org.redkale.inject.ResourceFactory;
import org.redkale.util.Environment;
import org.redkale.util.MultiHashKey;
import org.redkale.util.ThrowSupplier;
@@ -37,6 +39,8 @@ public class CacheAction {
private final CacheEntry cached;
+ private final Method method;
+
// Supplier对象的类型
private final Type resultType;
@@ -55,10 +59,6 @@ public class CacheAction {
// 获取动态的字段名
private final String fieldName;
- // 方法参数类型
- @Nullable
- private final Class[] paramTypes;
-
// 方法参数名
@Nullable
private final String[] paramNames;
@@ -69,8 +69,11 @@ public class CacheAction {
// 模板key
String templetKey;
- // 缓存的key
- private MultiHashKey dynKey;
+ // 缓存key生成器
+ private CacheKeyGenerator keyGenerator;
+
+ // 父对象
+ private Object service;
// 本地缓存过期时长,Duration.ZERO为永不过期,为null表示不本地缓存
private Duration localExpire;
@@ -78,34 +81,33 @@ public class CacheAction {
// 远程缓存过期时长,Duration.ZERO为永不过期,为null表示不远程缓存
private Duration remoteExpire;
- CacheAction(
- CacheEntry cached,
- Type returnType,
- Class serviceClass,
- Class[] paramTypes,
- String[] paramNames,
- String methodName,
- String fieldName) {
+ CacheAction(CacheEntry cached, Method method, Class serviceClass, String[] paramNames, String fieldName) {
this.cached = cached;
+ this.method = method;
this.nullable = cached.isNullable();
this.serviceClass = Objects.requireNonNull(serviceClass);
- this.paramTypes = paramTypes;
this.paramNames = paramNames;
- this.methodName = Objects.requireNonNull(methodName);
+ this.methodName = method.getName();
this.fieldName = Objects.requireNonNull(fieldName);
this.templetKey = cached.getKey();
+ Type returnType = method.getGenericReturnType();
this.async = CompletableFuture.class.isAssignableFrom(TypeToken.typeToClass(returnType));
this.resultType = this.async ? ((ParameterizedType) returnType).getActualTypeArguments()[0] : returnType;
}
- void init() {
+ void init(ResourceFactory resourceFactory, Object service) {
this.hash = cached.getHash().trim().isEmpty() || CacheManager.DEFAULT_HASH.equals(cached.getHash())
? CacheManager.DEFAULT_HASH
: environment.getPropertyValue(cached.getHash());
String key = environment.getPropertyValue(cached.getKey());
this.templetKey = key;
- this.dynKey = MultiHashKey.create(paramNames, key);
- this.localExpire = createDuration(cached.getLocalExpire());
+ if (key.startsWith("@")) { // 动态加载缓存key生成器
+ String generatorName = key.substring(1);
+ this.keyGenerator = resourceFactory.findChild(generatorName, CacheKeyGenerator.class);
+ } else {
+ MultiHashKey dynKey = MultiHashKey.create(paramNames, key);
+ this.keyGenerator = (t, a, args) -> dynKey.keyFor(args);
+ }
this.remoteExpire = createDuration(cached.getRemoteExpire());
}
@@ -114,10 +116,22 @@ public class CacheAction {
if (async) {
ThrowSupplier supplier0 = supplier;
return (T) manager.bothGetSetAsync(
- hash, dynKey.keyFor(args), resultType, nullable, localExpire, remoteExpire, supplier0);
+ hash,
+ keyGenerator.generate(service, this, args),
+ resultType,
+ nullable,
+ localExpire,
+ remoteExpire,
+ supplier0);
} else {
return manager.bothGetSet(
- hash, dynKey.keyFor(args), resultType, nullable, localExpire, remoteExpire, supplier);
+ hash,
+ keyGenerator.generate(service, this, args),
+ resultType,
+ nullable,
+ localExpire,
+ remoteExpire,
+ supplier);
}
}
@@ -146,14 +160,23 @@ public class CacheAction {
}
}
+ public CacheEntry getCached() {
+ return cached;
+ }
+
+ public Method getMethod() {
+ return method;
+ }
+
@Override
public String toString() {
return "{"
+ "\"serviceClass\":" + serviceClass.getName()
+ ",\"methodName\":\"" + methodName + "\""
+ ",\"fieldName\":\"" + fieldName + "\""
- + ",\"paramTypes\":" + JsonConvert.root().convertTo(paramTypes)
+ + ",\"paramTypes\":" + JsonConvert.root().convertTo(method.getParameterTypes())
+ ",\"paramNames\":" + JsonConvert.root().convertTo(paramNames)
+ + ",\"templetKey\":\"" + templetKey + "\""
+ ",\"resultType\":\"" + resultType + "\""
+ ",\"cache\":" + cached
+ "}";
diff --git a/src/main/java/org/redkale/cache/spi/CacheAsmMethodBoost.java b/src/main/java/org/redkale/cache/spi/CacheAsmMethodBoost.java
index 55613647a..4f0ce248b 100644
--- a/src/main/java/org/redkale/cache/spi/CacheAsmMethodBoost.java
+++ b/src/main/java/org/redkale/cache/spi/CacheAsmMethodBoost.java
@@ -169,13 +169,7 @@ public class CacheAsmMethodBoost extends AsmMethodBoost {
mv.visitMaxs(20, 20);
mv.visitEnd();
CacheAction action = new CacheAction(
- new CacheEntry(cached),
- method.getGenericReturnType(),
- serviceType,
- method.getParameterTypes(),
- methodBean.fieldNameArray(),
- method.getName(),
- dynFieldName);
+ new CacheEntry(cached), method, serviceType, methodBean.fieldNameArray(), dynFieldName);
actions.put(dynFieldName, action);
}
{ // ThrowSupplier
@@ -223,27 +217,24 @@ public class CacheAsmMethodBoost extends AsmMethodBoost {
String dynFieldName = cached.dynField();
AsmMethodBean methodBean = AsmMethodBean.get(methodBeans, method);
CacheAction action = new CacheAction(
- new CacheEntry(cached),
- method.getGenericReturnType(),
- serviceType,
- method.getParameterTypes(),
- methodBean.fieldNameArray(),
- method.getName(),
- dynFieldName);
- action.init();
- if (action.templetKey.indexOf('{') < 0 && method.getParameterCount() > 0) {
- // 一般有参数的方法,Cached.key应该是动态的
- logger.log(
- Level.WARNING,
- method + " has parameters but @" + Cached.class.getSimpleName()
- + ".key not contains parameter");
- }
+ new CacheEntry(cached), method, serviceType, methodBean.fieldNameArray(), dynFieldName);
actionMap.put(dynFieldName, action);
}
}
}
actionMap.forEach((field, action) -> {
try {
+ resourceFactory.inject(action);
+ action.init(resourceFactory, service);
+ if (action.templetKey.indexOf('@') < 0
+ && action.templetKey.indexOf('{') < 0
+ && action.getMethod().getParameterCount() > 0) {
+ // 一般有参数的方法,Cached.key应该是动态的
+ logger.log(
+ Level.WARNING,
+ action.getMethod() + " has parameters but @" + Cached.class.getSimpleName()
+ + ".key not contains parameter");
+ }
Field c = clazz.getDeclaredField(field);
c.setAccessible(true);
resourceFactory.inject(action);
diff --git a/src/main/java/org/redkale/cache/spi/CacheEntry.java b/src/main/java/org/redkale/cache/spi/CacheEntry.java
index 129745133..bdb02f29f 100644
--- a/src/main/java/org/redkale/cache/spi/CacheEntry.java
+++ b/src/main/java/org/redkale/cache/spi/CacheEntry.java
@@ -46,50 +46,26 @@ public class CacheEntry {
return key;
}
- public void setKey(String key) {
- this.key = key;
- }
-
public String getHash() {
return hash;
}
- public void setHash(String hash) {
- this.hash = hash;
- }
-
public String getLocalExpire() {
return localExpire;
}
- public void setLocalExpire(String localExpire) {
- this.localExpire = localExpire;
- }
-
public String getRemoteExpire() {
return remoteExpire;
}
- public void setRemoteExpire(String remoteExpire) {
- this.remoteExpire = remoteExpire;
- }
-
public TimeUnit getTimeUnit() {
return timeUnit;
}
- public void setTimeUnit(TimeUnit timeUnit) {
- this.timeUnit = timeUnit;
- }
-
public boolean isNullable() {
return nullable;
}
- public void setNullable(boolean nullable) {
- this.nullable = nullable;
- }
-
@Override
public String toString() {
return JsonConvert.root().convertTo(this);
diff --git a/src/main/java/org/redkale/cache/spi/CacheKeyGenerator.java b/src/main/java/org/redkale/cache/spi/CacheKeyGenerator.java
new file mode 100644
index 000000000..8671a3d55
--- /dev/null
+++ b/src/main/java/org/redkale/cache/spi/CacheKeyGenerator.java
@@ -0,0 +1,39 @@
+/*
+
+*/
+
+package org.redkale.cache.spi;
+
+/**
+ * 缓存key生成器
+ *
+ * @see org.redkale.cache.Cached#key()
+ *
+ *
详情见: https://redkale.org
+ *
+ * @author zhangjx
+ * @since 2.8.0
+ */
+public interface CacheKeyGenerator {
+
+ /**
+ * 根据service和方法名生成key
+ *
+ * @param target service对象
+ * @param action CacheAction对象
+ * @param params 参数值
+ * @return key值
+ */
+ public String generate(Object target, CacheAction action, Object... params);
+
+ /**
+ * 生成器的名字
+ *
+ * @see org.redkale.cache.Cached#key()
+ *
+ * @return name
+ */
+ default String name() {
+ return "";
+ }
+}
diff --git a/src/main/java/org/redkale/cache/spi/CacheModuleEngine.java b/src/main/java/org/redkale/cache/spi/CacheModuleEngine.java
index bd8568f8a..56a700790 100644
--- a/src/main/java/org/redkale/cache/spi/CacheModuleEngine.java
+++ b/src/main/java/org/redkale/cache/spi/CacheModuleEngine.java
@@ -3,18 +3,26 @@
*/
package org.redkale.cache.spi;
+import java.lang.reflect.Field;
+import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
+import java.util.Objects;
import java.util.ServiceLoader;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.logging.Level;
import org.redkale.asm.AsmMethodBoost;
import org.redkale.boot.Application;
import org.redkale.boot.ModuleEngine;
import org.redkale.cache.CacheManager;
+import org.redkale.inject.ResourceFactory;
+import org.redkale.inject.ResourceTypeLoader;
import org.redkale.service.Service;
import org.redkale.util.AnyValue;
import org.redkale.util.InstanceProvider;
import org.redkale.util.RedkaleClassLoader;
+import org.redkale.util.RedkaleException;
/** @author zhangjx */
public class CacheModuleEngine extends ModuleEngine {
@@ -70,6 +78,50 @@ public class CacheModuleEngine extends ModuleEngine {
}
}
this.resourceFactory.register("", CacheManager.class, this.cacheManager);
+ ConcurrentHashMap