CacheDyn
This commit is contained in:
@@ -28,12 +28,22 @@ public interface AsmMethodBoost<T> {
|
|||||||
* 对方法进行动态加强处理
|
* 对方法进行动态加强处理
|
||||||
*
|
*
|
||||||
* @param cw 动态字节码Writer
|
* @param cw 动态字节码Writer
|
||||||
|
* @param newDynName 动态新类名
|
||||||
|
* @param fieldPrefix 动态字段的前缀
|
||||||
* @param method 操作的方法
|
* @param method 操作的方法
|
||||||
* @param newMethodName 新的方法名, 可能为null
|
* @param newMethodName 新的方法名, 可能为null
|
||||||
*
|
*
|
||||||
* @return 下一个新的方法名,不做任何处理应返回参数newMethodName
|
* @return 下一个新的方法名,不做任何处理应返回参数newMethodName
|
||||||
*/
|
*/
|
||||||
public String doMethod(ClassWriter cw, Method method, @Nullable String newMethodName);
|
public String doMethod(ClassWriter cw, String newDynName, String fieldPrefix, Method method, @Nullable String newMethodName);
|
||||||
|
|
||||||
|
/** 处理所有动态方法后调用
|
||||||
|
*
|
||||||
|
* @param cw 动态字节码Writer
|
||||||
|
* @param newDynName 动态新类名
|
||||||
|
* @param fieldPrefix 动态字段的前缀
|
||||||
|
*/
|
||||||
|
public void doAfterMethods(ClassWriter cw, String newDynName, String fieldPrefix);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 实例对象进行操作,通常用于给动态的字段赋值
|
* 实例对象进行操作,通常用于给动态的字段赋值
|
||||||
@@ -41,4 +51,54 @@ public interface AsmMethodBoost<T> {
|
|||||||
* @param service 实例对象
|
* @param service 实例对象
|
||||||
*/
|
*/
|
||||||
public void doInstance(T service);
|
public void doInstance(T service);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 生产动态字节码的方法扩展器, 可以进行方法加强动作
|
||||||
|
*
|
||||||
|
* @param <T> 泛型
|
||||||
|
*
|
||||||
|
* @since 2.8.0
|
||||||
|
*/
|
||||||
|
static class AsmMethodBoosts<T> implements AsmMethodBoost<T> {
|
||||||
|
|
||||||
|
private final AsmMethodBoost[] items;
|
||||||
|
|
||||||
|
public AsmMethodBoosts(Collection<AsmMethodBoost> list) {
|
||||||
|
this.items = list.toArray(new AsmMethodBoost[list.size()]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public AsmMethodBoosts(AsmMethodBoost... items) {
|
||||||
|
this.items = items;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String doMethod(ClassWriter cw, String newDynName, String fieldPrefix, Method method, String newMethodName) {
|
||||||
|
String newName = newMethodName;
|
||||||
|
for (AsmMethodBoost item : items) {
|
||||||
|
if (item != null) {
|
||||||
|
newName = item.doMethod(cw, newDynName, fieldPrefix, method, newName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return newName;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void doAfterMethods(ClassWriter cw, String newDynName, String fieldPrefix) {
|
||||||
|
for (AsmMethodBoost item : items) {
|
||||||
|
if (item != null) {
|
||||||
|
item.doAfterMethods(cw, newDynName, fieldPrefix);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void doInstance(T service) {
|
||||||
|
for (AsmMethodBoost item : items) {
|
||||||
|
if (item != null) {
|
||||||
|
item.doInstance(service);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,48 +0,0 @@
|
|||||||
/*
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
package org.redkale.asm;
|
|
||||||
|
|
||||||
import java.lang.reflect.Method;
|
|
||||||
import java.util.Collection;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 生产动态字节码的方法扩展器, 可以进行方法加强动作
|
|
||||||
*
|
|
||||||
* @param <T> 泛型
|
|
||||||
*
|
|
||||||
* @since 2.8.0
|
|
||||||
*/
|
|
||||||
class AsmMethodBoosts<T> implements AsmMethodBoost<T> {
|
|
||||||
|
|
||||||
private final AsmMethodBoost[] items;
|
|
||||||
|
|
||||||
public AsmMethodBoosts(Collection<AsmMethodBoost> list) {
|
|
||||||
this.items = list.toArray(new AsmMethodBoost[list.size()]);
|
|
||||||
}
|
|
||||||
|
|
||||||
public AsmMethodBoosts(AsmMethodBoost... items) {
|
|
||||||
this.items = items;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String doMethod(ClassWriter cw, Method method, String newMethodName) {
|
|
||||||
String newName = newMethodName;
|
|
||||||
for (AsmMethodBoost item : items) {
|
|
||||||
if (item != null) {
|
|
||||||
newName = item.doMethod(cw, method, newName);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return newName;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void doInstance(T service) {
|
|
||||||
for (AsmMethodBoost item : items) {
|
|
||||||
if (item != null) {
|
|
||||||
item.doInstance(service);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -7,7 +7,6 @@ package org.redkale.boot.watch;
|
|||||||
|
|
||||||
import java.lang.reflect.*;
|
import java.lang.reflect.*;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import org.redkale.annotation.Comment;
|
|
||||||
import org.redkale.annotation.*;
|
import org.redkale.annotation.*;
|
||||||
import org.redkale.boot.*;
|
import org.redkale.boot.*;
|
||||||
import org.redkale.convert.json.JsonConvert;
|
import org.redkale.convert.json.JsonConvert;
|
||||||
@@ -69,7 +68,7 @@ public class ServiceWatchService extends AbstractWatchService {
|
|||||||
}
|
}
|
||||||
} while ((clazz = clazz.getSuperclass()) != Object.class);
|
} while ((clazz = clazz.getSuperclass()) != Object.class);
|
||||||
if (fieldObj == null) {
|
if (fieldObj == null) {
|
||||||
return new RetResult(RET_WATCH_RUN_EXCEPTION, "run exception (" + String.valueOf(t) + ")");
|
return new RetResult(RET_WATCH_RUN_EXCEPTION, "run exception (" + t + ")");
|
||||||
}
|
}
|
||||||
fieldObj.setAccessible(true);
|
fieldObj.setAccessible(true);
|
||||||
fieldObj.set(dest, JsonConvert.root().convertFrom(fieldObj.getGenericType(), value));
|
fieldObj.set(dest, JsonConvert.root().convertFrom(fieldObj.getGenericType(), value));
|
||||||
@@ -117,7 +116,7 @@ public class ServiceWatchService extends AbstractWatchService {
|
|||||||
}
|
}
|
||||||
} while ((clazz = clazz.getSuperclass()) != Object.class);
|
} while ((clazz = clazz.getSuperclass()) != Object.class);
|
||||||
if (fieldObj == null) {
|
if (fieldObj == null) {
|
||||||
return new RetResult(RET_WATCH_RUN_EXCEPTION, "run exception (" + String.valueOf(t) + ")");
|
return new RetResult(RET_WATCH_RUN_EXCEPTION, "run exception (" + t + ")");
|
||||||
}
|
}
|
||||||
fieldObj.setAccessible(true);
|
fieldObj.setAccessible(true);
|
||||||
return new RetResult(fieldObj.get(dest));
|
return new RetResult(fieldObj.get(dest));
|
||||||
|
|||||||
155
src/main/java/org/redkale/cache/spi/CacheAsmMethodBoost.java
vendored
Normal file
155
src/main/java/org/redkale/cache/spi/CacheAsmMethodBoost.java
vendored
Normal file
@@ -0,0 +1,155 @@
|
|||||||
|
/*
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
package org.redkale.cache.spi;
|
||||||
|
|
||||||
|
import java.lang.annotation.Annotation;
|
||||||
|
import java.lang.reflect.Method;
|
||||||
|
import java.lang.reflect.Modifier;
|
||||||
|
import org.redkale.asm.AnnotationVisitor;
|
||||||
|
import org.redkale.asm.AsmMethodBoost;
|
||||||
|
import org.redkale.asm.Asms;
|
||||||
|
import org.redkale.asm.ClassWriter;
|
||||||
|
import org.redkale.asm.MethodDebugVisitor;
|
||||||
|
import static org.redkale.asm.Opcodes.ACC_PRIVATE;
|
||||||
|
import static org.redkale.asm.Opcodes.ACC_PROTECTED;
|
||||||
|
import static org.redkale.asm.Opcodes.ACC_PUBLIC;
|
||||||
|
import static org.redkale.asm.Opcodes.ALOAD;
|
||||||
|
import static org.redkale.asm.Opcodes.ARETURN;
|
||||||
|
import static org.redkale.asm.Opcodes.DLOAD;
|
||||||
|
import static org.redkale.asm.Opcodes.DRETURN;
|
||||||
|
import static org.redkale.asm.Opcodes.FLOAD;
|
||||||
|
import static org.redkale.asm.Opcodes.FRETURN;
|
||||||
|
import static org.redkale.asm.Opcodes.ILOAD;
|
||||||
|
import static org.redkale.asm.Opcodes.INVOKESPECIAL;
|
||||||
|
import static org.redkale.asm.Opcodes.IRETURN;
|
||||||
|
import static org.redkale.asm.Opcodes.LLOAD;
|
||||||
|
import static org.redkale.asm.Opcodes.LRETURN;
|
||||||
|
import static org.redkale.asm.Opcodes.RETURN;
|
||||||
|
import org.redkale.asm.Type;
|
||||||
|
import org.redkale.cache.Cached;
|
||||||
|
import org.redkale.util.RedkaleException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author zhangjx
|
||||||
|
*/
|
||||||
|
public class CacheAsmMethodBoost implements AsmMethodBoost {
|
||||||
|
|
||||||
|
protected final Class serviceType;
|
||||||
|
|
||||||
|
public CacheAsmMethodBoost(Class serviceType) {
|
||||||
|
this.serviceType = serviceType;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String doMethod(ClassWriter cw, String newDynName, String fieldPrefix, Method method, final String newMethodName) {
|
||||||
|
Cached cached = method.getAnnotation(Cached.class);
|
||||||
|
if (cached == null) {
|
||||||
|
return newMethodName;
|
||||||
|
}
|
||||||
|
if (Modifier.isFinal(method.getModifiers()) || Modifier.isStatic(method.getModifiers())) {
|
||||||
|
throw new RedkaleException("@" + Cached.class.getSimpleName() + " can not on final or static method, but on " + method);
|
||||||
|
}
|
||||||
|
if (!Modifier.isProtected(method.getModifiers()) && !Modifier.isPublic(method.getModifiers())) {
|
||||||
|
throw new RedkaleException("@" + Cached.class.getSimpleName() + " must on protected or public method, but on " + method);
|
||||||
|
}
|
||||||
|
int acc;
|
||||||
|
String nowMethodName;
|
||||||
|
if (newMethodName == null) {
|
||||||
|
nowMethodName = method.getName();
|
||||||
|
acc = Modifier.isProtected(method.getModifiers()) ? ACC_PROTECTED : ACC_PUBLIC;
|
||||||
|
} else {
|
||||||
|
acc = ACC_PRIVATE;
|
||||||
|
nowMethodName = newMethodName;
|
||||||
|
}
|
||||||
|
final String rsMethodName = method.getName() + "_cache";
|
||||||
|
{
|
||||||
|
final String cacheDynDesc = Type.getDescriptor(CacheDyn.class);
|
||||||
|
MethodDebugVisitor mv;
|
||||||
|
AnnotationVisitor av;
|
||||||
|
String[] exps = null;
|
||||||
|
Class<?>[] expTypes = method.getExceptionTypes();
|
||||||
|
if (expTypes.length > 0) {
|
||||||
|
exps = new String[expTypes.length];
|
||||||
|
for (int i = 0; i < expTypes.length; i++) {
|
||||||
|
exps[i] = expTypes[i].getName().replace('.', '/');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//需要定义一个新方法调用 this.rsMethodName
|
||||||
|
mv = new MethodDebugVisitor(cw.visitMethod(acc, nowMethodName, Type.getMethodDescriptor(method), null, exps));
|
||||||
|
//mv.setDebug(true);
|
||||||
|
{
|
||||||
|
av = mv.visitAnnotation(cacheDynDesc, true);
|
||||||
|
av.visitEnd();
|
||||||
|
final Annotation[] anns = method.getAnnotations();
|
||||||
|
for (Annotation ann : anns) {
|
||||||
|
if (ann.annotationType() != Cached.class) {
|
||||||
|
Asms.visitAnnotation(mv.visitAnnotation(Type.getDescriptor(ann.annotationType()), true), ann);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
{ //给参数加上原有的Annotation
|
||||||
|
final Annotation[][] anns = method.getParameterAnnotations();
|
||||||
|
for (int k = 0; k < anns.length; k++) {
|
||||||
|
for (Annotation ann : anns[k]) {
|
||||||
|
Asms.visitAnnotation(mv.visitParameterAnnotation(k, Type.getDescriptor(ann.annotationType()), true), ann);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mv.visitVarInsn(ALOAD, 0);
|
||||||
|
//传参数
|
||||||
|
Class[] paramTypes = method.getParameterTypes();
|
||||||
|
int insn = 0;
|
||||||
|
for (Class pt : paramTypes) {
|
||||||
|
insn++;
|
||||||
|
if (pt.isPrimitive()) {
|
||||||
|
if (pt == long.class) {
|
||||||
|
mv.visitVarInsn(LLOAD, insn++);
|
||||||
|
} else if (pt == float.class) {
|
||||||
|
mv.visitVarInsn(FLOAD, insn++);
|
||||||
|
} else if (pt == double.class) {
|
||||||
|
mv.visitVarInsn(DLOAD, insn++);
|
||||||
|
} else {
|
||||||
|
mv.visitVarInsn(ILOAD, insn);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
mv.visitVarInsn(ALOAD, insn);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mv.visitMethodInsn(INVOKESPECIAL, newDynName, rsMethodName, Type.getMethodDescriptor(method), false);
|
||||||
|
if (method.getGenericReturnType() == void.class) {
|
||||||
|
mv.visitInsn(RETURN);
|
||||||
|
} else {
|
||||||
|
Class returnclz = method.getReturnType();
|
||||||
|
if (returnclz.isPrimitive()) {
|
||||||
|
if (returnclz == long.class) {
|
||||||
|
mv.visitInsn(LRETURN);
|
||||||
|
} else if (returnclz == float.class) {
|
||||||
|
mv.visitInsn(FRETURN);
|
||||||
|
} else if (returnclz == double.class) {
|
||||||
|
mv.visitInsn(DRETURN);
|
||||||
|
} else {
|
||||||
|
mv.visitInsn(IRETURN);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
mv.visitInsn(ARETURN);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mv.visitMaxs(20, 20);
|
||||||
|
mv.visitEnd();
|
||||||
|
}
|
||||||
|
return rsMethodName;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void doAfterMethods(ClassWriter cw, String newDynName, String fieldPrefix) {
|
||||||
|
//do nothing
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void doInstance(Object service) {
|
||||||
|
//do nothing
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
22
src/main/java/org/redkale/cache/spi/CacheDyn.java
vendored
Normal file
22
src/main/java/org/redkale/cache/spi/CacheDyn.java
vendored
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
/*
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
package org.redkale.cache.spi;
|
||||||
|
|
||||||
|
import java.lang.annotation.Documented;
|
||||||
|
import static java.lang.annotation.ElementType.METHOD;
|
||||||
|
import java.lang.annotation.Inherited;
|
||||||
|
import java.lang.annotation.Retention;
|
||||||
|
import static java.lang.annotation.RetentionPolicy.RUNTIME;
|
||||||
|
import java.lang.annotation.Target;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author zhangjx
|
||||||
|
*/
|
||||||
|
@Inherited
|
||||||
|
@Documented
|
||||||
|
@Target({METHOD})
|
||||||
|
@Retention(RUNTIME)
|
||||||
|
public @interface CacheDyn {
|
||||||
|
}
|
||||||
@@ -7,6 +7,7 @@ import java.util.ArrayList;
|
|||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.ServiceLoader;
|
import java.util.ServiceLoader;
|
||||||
|
import org.redkale.asm.AsmMethodBoost;
|
||||||
import org.redkale.boot.Application;
|
import org.redkale.boot.Application;
|
||||||
import org.redkale.boot.ModuleEngine;
|
import org.redkale.boot.ModuleEngine;
|
||||||
import org.redkale.cache.CacheManager;
|
import org.redkale.cache.CacheManager;
|
||||||
@@ -48,6 +49,17 @@ public class CacheModuleEngine extends ModuleEngine {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 动态扩展类的方法
|
||||||
|
*
|
||||||
|
* @param serviceClass 类
|
||||||
|
*
|
||||||
|
* @return 方法动态扩展器
|
||||||
|
*/
|
||||||
|
public AsmMethodBoost createAsmMethodBoost(Class serviceClass) {
|
||||||
|
return new CacheAsmMethodBoost(serviceClass);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 结束Application.init方法前被调用
|
* 结束Application.init方法前被调用
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -556,6 +556,84 @@ public abstract class Sncp {
|
|||||||
mv.visitMaxs(1, 1);
|
mv.visitMaxs(1, 1);
|
||||||
mv.visitEnd();
|
mv.visitEnd();
|
||||||
}
|
}
|
||||||
|
if (methodBoost != null) {
|
||||||
|
Class clazz = serviceImplClass;
|
||||||
|
Set<String> methodKeys = new HashSet<>();
|
||||||
|
do {
|
||||||
|
for (final Method method : clazz.getDeclaredMethods()) {
|
||||||
|
String mk = Utility.methodKey(method);
|
||||||
|
if (methodKeys.contains(mk)) {
|
||||||
|
//跳过已处理的继承方法
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
methodKeys.add(mk);
|
||||||
|
String newMethodName = methodBoost.doMethod(cw, newDynName, FIELDPREFIX, method, null);
|
||||||
|
if (newMethodName != null) {
|
||||||
|
String[] exps = null;
|
||||||
|
Class<?>[] expTypes = method.getExceptionTypes();
|
||||||
|
if (expTypes.length > 0) {
|
||||||
|
exps = new String[expTypes.length];
|
||||||
|
for (int i = 0; i < expTypes.length; i++) {
|
||||||
|
exps[i] = expTypes[i].getName().replace('.', '/');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//需要定义一个新方法调用 super.method
|
||||||
|
mv = new MethodDebugVisitor(cw.visitMethod(ACC_PRIVATE, newMethodName, Type.getMethodDescriptor(method), null, exps));
|
||||||
|
//mv.setDebug(true);
|
||||||
|
{ //给参数加上原有的Annotation
|
||||||
|
final Annotation[][] anns = method.getParameterAnnotations();
|
||||||
|
for (int k = 0; k < anns.length; k++) {
|
||||||
|
for (Annotation ann : anns[k]) {
|
||||||
|
Asms.visitAnnotation(mv.visitParameterAnnotation(k, Type.getDescriptor(ann.annotationType()), true), ann);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mv.visitVarInsn(ALOAD, 0);
|
||||||
|
//传参数
|
||||||
|
Class[] paramTypes = method.getParameterTypes();
|
||||||
|
int insn = 0;
|
||||||
|
for (Class pt : paramTypes) {
|
||||||
|
insn++;
|
||||||
|
if (pt.isPrimitive()) {
|
||||||
|
if (pt == long.class) {
|
||||||
|
mv.visitVarInsn(LLOAD, insn++);
|
||||||
|
} else if (pt == float.class) {
|
||||||
|
mv.visitVarInsn(FLOAD, insn++);
|
||||||
|
} else if (pt == double.class) {
|
||||||
|
mv.visitVarInsn(DLOAD, insn++);
|
||||||
|
} else {
|
||||||
|
mv.visitVarInsn(ILOAD, insn);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
mv.visitVarInsn(ALOAD, insn);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mv.visitMethodInsn(INVOKESPECIAL, supDynName, method.getName(), Type.getMethodDescriptor(method), false);
|
||||||
|
if (method.getGenericReturnType() == void.class) {
|
||||||
|
mv.visitInsn(RETURN);
|
||||||
|
} else {
|
||||||
|
Class returnclz = method.getReturnType();
|
||||||
|
if (returnclz.isPrimitive()) {
|
||||||
|
if (returnclz == long.class) {
|
||||||
|
mv.visitInsn(LRETURN);
|
||||||
|
} else if (returnclz == float.class) {
|
||||||
|
mv.visitInsn(FRETURN);
|
||||||
|
} else if (returnclz == double.class) {
|
||||||
|
mv.visitInsn(DRETURN);
|
||||||
|
} else {
|
||||||
|
mv.visitInsn(IRETURN);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
mv.visitInsn(ARETURN);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mv.visitMaxs(20, 20);
|
||||||
|
mv.visitEnd();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} while ((clazz = clazz.getSuperclass()) != Object.class);
|
||||||
|
methodBoost.doAfterMethods(cw, newDynName, FIELDPREFIX);
|
||||||
|
}
|
||||||
cw.visitEnd();
|
cw.visitEnd();
|
||||||
byte[] bytes = cw.toByteArray();
|
byte[] bytes = cw.toByteArray();
|
||||||
Class<?> newClazz = new ClassLoader(loader) {
|
Class<?> newClazz = new ClassLoader(loader) {
|
||||||
|
|||||||
@@ -13,10 +13,12 @@ import java.time.Duration;
|
|||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
import java.time.ZoneId;
|
import java.time.ZoneId;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashSet;
|
||||||
import java.util.LinkedHashMap;
|
import java.util.LinkedHashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
import java.util.Set;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
import java.util.concurrent.ScheduledFuture;
|
import java.util.concurrent.ScheduledFuture;
|
||||||
import java.util.concurrent.ScheduledThreadPoolExecutor;
|
import java.util.concurrent.ScheduledThreadPoolExecutor;
|
||||||
@@ -131,15 +133,18 @@ public class ScheduleManagerService implements ScheduleManager, Service {
|
|||||||
Class clazz = service.getClass();
|
Class clazz = service.getClass();
|
||||||
WeakReference ref = new WeakReference(service);
|
WeakReference ref = new WeakReference(service);
|
||||||
AtomicInteger taskCount = new AtomicInteger();
|
AtomicInteger taskCount = new AtomicInteger();
|
||||||
|
Set<String> methodKeys = new HashSet<>();
|
||||||
do {
|
do {
|
||||||
for (final Method method : clazz.getDeclaredMethods()) {
|
for (final Method method : clazz.getDeclaredMethods()) {
|
||||||
if (method.getAnnotation(Scheduled.class) == null) {
|
if (method.getAnnotation(Scheduled.class) == null) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (tasks.containsKey(method.getName())) {
|
String mk = Utility.methodKey(method);
|
||||||
|
if (methodKeys.contains(mk)) {
|
||||||
//跳过已处理的继承方法
|
//跳过已处理的继承方法
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
methodKeys.add(mk);
|
||||||
if (method.getParameterCount() != 0
|
if (method.getParameterCount() != 0
|
||||||
&& (method.getParameterCount() == 1 && method.getParameterTypes()[0] == ScheduleEvent.class)) {
|
&& (method.getParameterCount() == 1 && method.getParameterTypes()[0] == ScheduleEvent.class)) {
|
||||||
throw new RedkaleException("@" + Scheduled.class.getSimpleName() + " must be on non-parameter or "
|
throw new RedkaleException("@" + Scheduled.class.getSimpleName() + " must be on non-parameter or "
|
||||||
|
|||||||
@@ -444,6 +444,23 @@ public final class Utility {
|
|||||||
return virtualExecutorConsumer == null ? defaultExecutorConsumer : virtualExecutorConsumer;
|
return virtualExecutorConsumer == null ? defaultExecutorConsumer : virtualExecutorConsumer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 构建method的唯一key,用于遍历类及父类的所有方法,key过滤重载方法
|
||||||
|
*
|
||||||
|
* @param method 方法
|
||||||
|
*
|
||||||
|
* @return key
|
||||||
|
*/
|
||||||
|
public static String methodKey(Method method) {
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
sb.append(method.getName());
|
||||||
|
sb.append('-').append(method.getParameterCount());
|
||||||
|
for (Class c : method.getParameterTypes()) {
|
||||||
|
sb.append('-').append(c.getName());
|
||||||
|
}
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 返回第一个不为null的对象
|
* 返回第一个不为null的对象
|
||||||
*
|
*
|
||||||
|
|||||||
Reference in New Issue
Block a user