From 382ad87c5fb07a914ca6f6284e860b2231b2104e Mon Sep 17 00:00:00 2001 From: redkale Date: Thu, 21 Dec 2023 14:44:52 +0800 Subject: [PATCH] CacheAction --- .../java/org/redkale/asm/AsmMethodBean.java | 4 + .../java/org/redkale/asm/AsmMethodBoost.java | 3 +- .../org/redkale/cache/spi/CacheAction.java | 35 +++--- .../cache/spi/CacheAsmMethodBoost.java | 47 ++++++-- .../org/redkale/cache/spi/CacheEntry.java | 101 ++++++++++++++++++ .../org/redkale/cache/spi/CacheExpire.java | 1 + 6 files changed, 165 insertions(+), 26 deletions(-) create mode 100644 src/main/java/org/redkale/cache/spi/CacheEntry.java diff --git a/src/main/java/org/redkale/asm/AsmMethodBean.java b/src/main/java/org/redkale/asm/AsmMethodBean.java index 16eafbb4c..2d228b077 100644 --- a/src/main/java/org/redkale/asm/AsmMethodBean.java +++ b/src/main/java/org/redkale/asm/AsmMethodBean.java @@ -50,6 +50,10 @@ public class AsmMethodBean { } } + public String[] fieldNameArray() { + return fieldNames == null ? null : fieldNames.toArray(new String[fieldNames.size()]); + } + public List getFieldNames() { return fieldNames; } diff --git a/src/main/java/org/redkale/asm/AsmMethodBoost.java b/src/main/java/org/redkale/asm/AsmMethodBoost.java index 569217484..7dccb2cad 100644 --- a/src/main/java/org/redkale/asm/AsmMethodBoost.java +++ b/src/main/java/org/redkale/asm/AsmMethodBoost.java @@ -101,7 +101,8 @@ public abstract class AsmMethodBoost { * @param newDynName 动态新类名 * @param fieldPrefix 动态字段的前缀 */ - public abstract void doAfterMethods(ClassWriter cw, String newDynName, String fieldPrefix); + public void doAfterMethods(ClassWriter cw, String newDynName, String fieldPrefix) { + } /** * 实例对象进行操作,通常用于给动态的字段赋值 diff --git a/src/main/java/org/redkale/cache/spi/CacheAction.java b/src/main/java/org/redkale/cache/spi/CacheAction.java index 34f56c2eb..df482c44c 100644 --- a/src/main/java/org/redkale/cache/spi/CacheAction.java +++ b/src/main/java/org/redkale/cache/spi/CacheAction.java @@ -12,7 +12,6 @@ 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; @@ -38,7 +37,7 @@ public class CacheAction { @Resource private CacheManager manager; - private final Cached cached; + private final CacheEntry cached; //Supplier对象的类型 private final Type resultType; @@ -55,6 +54,9 @@ public class CacheAction { //无法获取动态的Method,只能存方法名 private final String methodName; + //获取动态的字段名 + private final String fieldName; + //方法参数类型 @Nullable private final Class[] paramTypes; @@ -66,9 +68,6 @@ public class CacheAction { //缓存的hash private String hash; - //缓存的key - private String key; - //缓存的key private MultiHashKey dynKey; @@ -78,25 +77,27 @@ public class CacheAction { //远程缓存过期时长 private Duration remoteExpire; - CacheAction(Cached cached, Type returnType, Class serviceClass, Class[] paramTypes, String[] paramNames, String methodName) { + CacheAction(CacheEntry cached, Type returnType, Class serviceClass, Class[] paramTypes, + String[] paramNames, String methodName, String fieldName) { this.cached = cached; - this.nullable = cached.nullable(); + this.nullable = cached.isNullable(); this.serviceClass = Objects.requireNonNull(serviceClass); this.paramTypes = paramTypes; this.paramNames = paramNames; this.methodName = Objects.requireNonNull(methodName); + this.fieldName = Objects.requireNonNull(fieldName); this.async = CompletableFuture.class.isAssignableFrom(TypeToken.typeToClass(returnType)); this.resultType = this.async ? ((ParameterizedType) returnType).getActualTypeArguments()[0] : returnType; } void init() { - this.hash = cached.hash().trim().isEmpty() + this.hash = cached.getHash().trim().isEmpty() ? Sncp.getResourceType(serviceClass).getSimpleName() - : environment.getPropertyValue(cached.hash()); - this.key = environment.getPropertyValue(cached.key()); + : environment.getPropertyValue(cached.getHash()); + String key = environment.getPropertyValue(cached.getKey()); this.dynKey = MultiHashKey.create(paramNames, key); - this.localExpire = createDuration(cached.localExpire()); - this.remoteExpire = createDuration(cached.remoteExpire()); + this.localExpire = createDuration(cached.getLocalExpire()); + this.remoteExpire = createDuration(cached.getRemoteExpire()); } public T get(Supplier supplier, Object... args) { @@ -115,7 +116,7 @@ public class CacheAction { } else if ("0".equals(str)) { return Duration.ZERO; } else { - return Duration.ofMillis(cached.timeUnit().toMillis(Long.parseLong(str))); + return Duration.ofMillis(cached.getTimeUnit().toMillis(Long.parseLong(str))); } } @@ -124,14 +125,10 @@ public class CacheAction { return "{" + "\"serviceClass\":" + serviceClass.getName() + ",\"methodName\":\"" + methodName + "\"" + + ",\"fieldName\":\"" + fieldName + "\"" + ",\"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() + + ",\"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 a3d895a6b..3ff71899d 100644 --- a/src/main/java/org/redkale/cache/spi/CacheAsmMethodBoost.java +++ b/src/main/java/org/redkale/cache/spi/CacheAsmMethodBoost.java @@ -4,9 +4,12 @@ package org.redkale.cache.spi; import java.lang.annotation.Annotation; +import java.lang.reflect.Field; import java.lang.reflect.Method; import java.lang.reflect.Modifier; +import java.util.LinkedHashMap; import java.util.List; +import java.util.Map; import java.util.concurrent.CompletableFuture; import org.redkale.asm.AnnotationVisitor; import org.redkale.asm.AsmMethodBean; @@ -20,6 +23,7 @@ import static org.redkale.asm.Opcodes.*; import org.redkale.asm.Type; import org.redkale.cache.Cached; import org.redkale.inject.ResourceFactory; +import org.redkale.util.RedkaleClassLoader; import org.redkale.util.RedkaleException; import org.redkale.util.TypeToken; @@ -34,6 +38,8 @@ public class CacheAsmMethodBoost extends AsmMethodBoost { private static final List> FILTER_ANN = List.of(Cached.class, DynForCache.class); + private Map actionMap; + public CacheAsmMethodBoost(Class serviceType) { super(serviceType); } @@ -45,6 +51,11 @@ public class CacheAsmMethodBoost extends AsmMethodBoost { @Override public String doMethod(ClassWriter cw, String newDynName, String fieldPrefix, List filterAnns, Method method, final String newMethodName) { + Map actions = this.actionMap; + if (actions == null) { + actions = new LinkedHashMap<>(); + this.actionMap = actions; + } Cached cached = method.getAnnotation(Cached.class); if (cached == null) { return newMethodName; @@ -61,7 +72,6 @@ public class CacheAsmMethodBoost extends AsmMethodBoost { if (method.getReturnType() == void.class || FUTURE_VOID.equals(method.getGenericReturnType())) { throw new RedkaleException("@" + Cached.class.getSimpleName() + " cannot on void method, but on " + method); } - final String rsMethodName = method.getName() + "_afterCache"; final String dynFieldName = fieldPrefix + "_" + method.getName() + "CacheAction" + fieldIndex.incrementAndGet(); { //定义一个新方法调用 this.rsMethodName @@ -82,6 +92,9 @@ public class CacheAsmMethodBoost extends AsmMethodBoost { visitInsnReturn(mv, method, l0, insns, methodBean); mv.visitMaxs(20, 20); mv.visitEnd(); + CacheAction action = new CacheAction(new CacheEntry(cached), method.getGenericReturnType(), serviceType, + method.getParameterTypes(), methodBean.fieldNameArray(), method.getName(), dynFieldName); + actions.put(dynFieldName, action); } { //定义字段 FieldVisitor fv = cw.visitField(ACC_PRIVATE, dynFieldName, Type.getDescriptor(CacheAction.class), null, null); @@ -90,13 +103,35 @@ public class CacheAsmMethodBoost extends AsmMethodBoost { return rsMethodName; } - @Override - public void doAfterMethods(ClassWriter cw, String newDynName, String fieldPrefix) { - //do nothing - } - @Override public void doInstance(ResourceFactory resourceFactory, Object service) { + Class clazz = service.getClass(); + if (actionMap == null) { //为null表示没有调用过doMethod, 动态类在编译是已经生成好了 + actionMap = new LinkedHashMap<>(); + Map methodBeans = AsmMethodBoost.getMethodBeans(clazz); + for (final Method method : clazz.getDeclaredMethods()) { + DynForCache cached = method.getAnnotation(DynForCache.class); + if (cached != null) { + 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); + actionMap.put(dynFieldName, action); + } + } + } + actionMap.forEach((field, action) -> { + try { + Field c = clazz.getDeclaredField(field); + c.setAccessible(true); + resourceFactory.inject(action); + action.init(); + c.set(service, action); + RedkaleClassLoader.putReflectionField(clazz.getName(), c); + } catch (Exception e) { + throw new RedkaleException("field (" + field + ") in " + clazz.getName() + " set error", e); + } + }); //do nothing } diff --git a/src/main/java/org/redkale/cache/spi/CacheEntry.java b/src/main/java/org/redkale/cache/spi/CacheEntry.java new file mode 100644 index 000000000..6ae16cec9 --- /dev/null +++ b/src/main/java/org/redkale/cache/spi/CacheEntry.java @@ -0,0 +1,101 @@ +/* + * + */ +package org.redkale.cache.spi; + +import java.util.concurrent.TimeUnit; +import org.redkale.cache.Cached; +import org.redkale.convert.json.JsonConvert; + +/** + * + * @author zhangjx + */ +public class CacheEntry { + + private String key; + + private String hash; + + private String localExpire; + + private String remoteExpire; + + private TimeUnit timeUnit; + + private boolean nullable; + + public CacheEntry() { + } + + public CacheEntry(DynForCache cached) { + this.key = cached.key(); + this.hash = cached.hash(); + this.localExpire = cached.localExpire(); + this.remoteExpire = cached.remoteExpire(); + this.timeUnit = cached.timeUnit(); + this.nullable = cached.nullable(); + } + + public CacheEntry(Cached cached) { + this.key = cached.key(); + this.hash = cached.hash(); + this.localExpire = cached.localExpire(); + this.remoteExpire = cached.remoteExpire(); + this.timeUnit = cached.timeUnit(); + this.nullable = cached.nullable(); + } + + public String getKey() { + 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/CacheExpire.java b/src/main/java/org/redkale/cache/spi/CacheExpire.java index 050a8adff..1626fe24b 100644 --- a/src/main/java/org/redkale/cache/spi/CacheExpire.java +++ b/src/main/java/org/redkale/cache/spi/CacheExpire.java @@ -37,6 +37,7 @@ public class CacheExpire { this.time = time; } + @Override public String toString() { return JsonConvert.root().convertTo(this); }