AsmMethodBoost
This commit is contained in:
@@ -6,12 +6,28 @@ package org.redkale.asm;
|
|||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.lang.annotation.Annotation;
|
import java.lang.annotation.Annotation;
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
|
import java.lang.reflect.Modifier;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
import org.redkale.annotation.Nullable;
|
import org.redkale.annotation.Nullable;
|
||||||
|
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.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.util.Utility;
|
import org.redkale.util.Utility;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -21,7 +37,15 @@ import org.redkale.util.Utility;
|
|||||||
*
|
*
|
||||||
* @since 2.8.0
|
* @since 2.8.0
|
||||||
*/
|
*/
|
||||||
public interface AsmMethodBoost<T> {
|
public abstract class AsmMethodBoost<T> {
|
||||||
|
|
||||||
|
protected final AtomicInteger fieldIndex = new AtomicInteger();
|
||||||
|
|
||||||
|
protected final Class serviceType;
|
||||||
|
|
||||||
|
protected AsmMethodBoost(Class serviceType) {
|
||||||
|
this.serviceType = serviceType;
|
||||||
|
}
|
||||||
|
|
||||||
public static AsmMethodBoost create(Collection<AsmMethodBoost> list) {
|
public static AsmMethodBoost create(Collection<AsmMethodBoost> list) {
|
||||||
return new AsmMethodBoosts(list);
|
return new AsmMethodBoosts(list);
|
||||||
@@ -31,6 +55,124 @@ public interface AsmMethodBoost<T> {
|
|||||||
return new AsmMethodBoosts(items);
|
return new AsmMethodBoosts(items);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected AsmMethodBean getMethodBean(Method method) {
|
||||||
|
Map<String, AsmMethodBean> methodBeans = AsmMethodBoost.getMethodBeans(serviceType);
|
||||||
|
return AsmMethodBean.get(methodBeans, method);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected MethodVisitor createMethodVisitor(ClassWriter cw, Method method, String newMethodName, AsmMethodBean methodBean) {
|
||||||
|
return new MethodDebugVisitor(cw.visitMethod(getAcc(method, newMethodName),
|
||||||
|
getNowMethodName(method, newMethodName), Type.getMethodDescriptor(method),
|
||||||
|
getMethodSignature(method, methodBean), getMethodExceptions(method, methodBean)));
|
||||||
|
}
|
||||||
|
|
||||||
|
protected int getAcc(Method method, String newMethodName) {
|
||||||
|
if (newMethodName != null) {
|
||||||
|
return ACC_PRIVATE;
|
||||||
|
}
|
||||||
|
return Modifier.isProtected(method.getModifiers()) ? ACC_PROTECTED : ACC_PUBLIC;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected String getNowMethodName(Method method, String newMethodName) {
|
||||||
|
return newMethodName == null ? method.getName() : newMethodName;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected String getMethodSignature(Method method, AsmMethodBean methodBean) {
|
||||||
|
return methodBean != null ? methodBean.getSignature() : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected String[] getMethodExceptions(Method method, AsmMethodBean methodBean) {
|
||||||
|
if (methodBean == null) {
|
||||||
|
String[] exceptions = null;
|
||||||
|
Class<?>[] expTypes = method.getExceptionTypes();
|
||||||
|
if (expTypes.length > 0) {
|
||||||
|
exceptions = new String[expTypes.length];
|
||||||
|
for (int i = 0; i < expTypes.length; i++) {
|
||||||
|
exceptions[i] = expTypes[i].getName().replace('.', '/');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return exceptions;
|
||||||
|
} else {
|
||||||
|
return methodBean.getExceptions();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void visitRawAnnotation(Method method, String newMethodName, MethodVisitor mv, Class selfAnnType, List filterAnns) {
|
||||||
|
if (newMethodName == null) {
|
||||||
|
//给方法加上原有的Annotation
|
||||||
|
final Annotation[] anns = method.getAnnotations();
|
||||||
|
for (Annotation ann : anns) {
|
||||||
|
if (ann.annotationType() != selfAnnType
|
||||||
|
&& (filterAnns == null || !filterAnns.contains(ann.annotationType()))) {
|
||||||
|
Asms.visitAnnotation(mv.visitAnnotation(Type.getDescriptor(ann.annotationType()), true), ann);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//给参数加上原有的Annotation
|
||||||
|
final Annotation[][] annss = method.getParameterAnnotations();
|
||||||
|
for (int k = 0; k < annss.length; k++) {
|
||||||
|
for (Annotation ann : annss[k]) {
|
||||||
|
Asms.visitAnnotation(mv.visitParameterAnnotation(k, Type.getDescriptor(ann.annotationType()), true), ann);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected List<Integer> visitVarInsnParamTypes(MethodVisitor mv, Method method) {
|
||||||
|
//传参数
|
||||||
|
Class[] paramTypes = method.getParameterTypes();
|
||||||
|
List<Integer> insns = new ArrayList<>();
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
insns.add(insn);
|
||||||
|
}
|
||||||
|
return insns;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void visitInsnReturn(MethodVisitor mv, Method method, Label l0, List<Integer> insns, AsmMethodBean methodBean) {
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Class[] paramTypes = method.getParameterTypes();
|
||||||
|
if (methodBean != null && paramTypes.length > 0) {
|
||||||
|
Label l2 = new Label();
|
||||||
|
mv.visitLabel(l2);
|
||||||
|
//mv.visitLocalVariable("this", thisClassDesc, null, l0, l2, 0);
|
||||||
|
List<String> fieldNames = methodBean.getFieldNames();
|
||||||
|
for (int i = 0; i < paramTypes.length; i++) {
|
||||||
|
mv.visitLocalVariable(fieldNames.get(i), Type.getDescriptor(paramTypes[i]), null, l0, l2, insns.get(i));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* 返回一个类所有方法的字节信息, key为: method.getName+':'+Type.getMethodDescriptor(method)
|
* 返回一个类所有方法的字节信息, key为: method.getName+':'+Type.getMethodDescriptor(method)
|
||||||
@@ -53,7 +195,7 @@ public interface AsmMethodBoost<T> {
|
|||||||
*
|
*
|
||||||
* @return 需要屏蔽的注解
|
* @return 需要屏蔽的注解
|
||||||
*/
|
*/
|
||||||
public List<Class<? extends Annotation>> filterMethodAnnotations(Method method);
|
public abstract List<Class<? extends Annotation>> filterMethodAnnotations(Method method);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 对方法进行动态加强处理
|
* 对方法进行动态加强处理
|
||||||
@@ -67,7 +209,7 @@ public interface AsmMethodBoost<T> {
|
|||||||
*
|
*
|
||||||
* @return 下一个新的方法名,不做任何处理应返回参数newMethodName
|
* @return 下一个新的方法名,不做任何处理应返回参数newMethodName
|
||||||
*/
|
*/
|
||||||
public String doMethod(ClassWriter cw, String newDynName, String fieldPrefix,
|
public abstract String doMethod(ClassWriter cw, String newDynName, String fieldPrefix,
|
||||||
List<Class<? extends Annotation>> filterAnns, Method method, @Nullable String newMethodName);
|
List<Class<? extends Annotation>> filterAnns, Method method, @Nullable String newMethodName);
|
||||||
|
|
||||||
/** 处理所有动态方法后调用
|
/** 处理所有动态方法后调用
|
||||||
@@ -76,14 +218,14 @@ public interface AsmMethodBoost<T> {
|
|||||||
* @param newDynName 动态新类名
|
* @param newDynName 动态新类名
|
||||||
* @param fieldPrefix 动态字段的前缀
|
* @param fieldPrefix 动态字段的前缀
|
||||||
*/
|
*/
|
||||||
public void doAfterMethods(ClassWriter cw, String newDynName, String fieldPrefix);
|
public abstract void doAfterMethods(ClassWriter cw, String newDynName, String fieldPrefix);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 实例对象进行操作,通常用于给动态的字段赋值
|
* 实例对象进行操作,通常用于给动态的字段赋值
|
||||||
*
|
*
|
||||||
* @param service 实例对象
|
* @param service 实例对象
|
||||||
*/
|
*/
|
||||||
public void doInstance(T service);
|
public abstract void doInstance(T service);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 生产动态字节码的方法扩展器, 可以进行方法加强动作
|
* 生产动态字节码的方法扩展器, 可以进行方法加强动作
|
||||||
@@ -92,15 +234,17 @@ public interface AsmMethodBoost<T> {
|
|||||||
*
|
*
|
||||||
* @since 2.8.0
|
* @since 2.8.0
|
||||||
*/
|
*/
|
||||||
static class AsmMethodBoosts<T> implements AsmMethodBoost<T> {
|
static class AsmMethodBoosts<T> extends AsmMethodBoost<T> {
|
||||||
|
|
||||||
private final AsmMethodBoost[] items;
|
private final AsmMethodBoost[] items;
|
||||||
|
|
||||||
public AsmMethodBoosts(Collection<AsmMethodBoost> list) {
|
public AsmMethodBoosts(Collection<AsmMethodBoost> list) {
|
||||||
|
super(null);
|
||||||
this.items = list.toArray(new AsmMethodBoost[list.size()]);
|
this.items = list.toArray(new AsmMethodBoost[list.size()]);
|
||||||
}
|
}
|
||||||
|
|
||||||
public AsmMethodBoosts(AsmMethodBoost... items) {
|
public AsmMethodBoosts(AsmMethodBoost... items) {
|
||||||
|
super(null);
|
||||||
this.items = items;
|
this.items = items;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -6,10 +6,7 @@ package org.redkale.cache.spi;
|
|||||||
import java.lang.annotation.Annotation;
|
import java.lang.annotation.Annotation;
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
import java.lang.reflect.Modifier;
|
import java.lang.reflect.Modifier;
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
|
||||||
import java.util.concurrent.atomic.AtomicInteger;
|
|
||||||
import org.redkale.asm.AnnotationVisitor;
|
import org.redkale.asm.AnnotationVisitor;
|
||||||
import org.redkale.asm.AsmMethodBean;
|
import org.redkale.asm.AsmMethodBean;
|
||||||
import org.redkale.asm.AsmMethodBoost;
|
import org.redkale.asm.AsmMethodBoost;
|
||||||
@@ -17,7 +14,7 @@ import org.redkale.asm.Asms;
|
|||||||
import org.redkale.asm.ClassWriter;
|
import org.redkale.asm.ClassWriter;
|
||||||
import org.redkale.asm.FieldVisitor;
|
import org.redkale.asm.FieldVisitor;
|
||||||
import org.redkale.asm.Label;
|
import org.redkale.asm.Label;
|
||||||
import org.redkale.asm.MethodDebugVisitor;
|
import org.redkale.asm.MethodVisitor;
|
||||||
import static org.redkale.asm.Opcodes.*;
|
import static org.redkale.asm.Opcodes.*;
|
||||||
import org.redkale.asm.Type;
|
import org.redkale.asm.Type;
|
||||||
import org.redkale.cache.Cached;
|
import org.redkale.cache.Cached;
|
||||||
@@ -27,16 +24,12 @@ import org.redkale.util.RedkaleException;
|
|||||||
*
|
*
|
||||||
* @author zhangjx
|
* @author zhangjx
|
||||||
*/
|
*/
|
||||||
public class CacheAsmMethodBoost implements AsmMethodBoost {
|
public class CacheAsmMethodBoost extends AsmMethodBoost {
|
||||||
|
|
||||||
private static final List<Class<? extends Annotation>> FILTER_ANN = List.of(Cached.class, DynForCache.class);
|
private static final List<Class<? extends Annotation>> FILTER_ANN = List.of(Cached.class, DynForCache.class);
|
||||||
|
|
||||||
private final AtomicInteger fieldIndex = new AtomicInteger();
|
|
||||||
|
|
||||||
protected final Class serviceType;
|
|
||||||
|
|
||||||
public CacheAsmMethodBoost(Class serviceType) {
|
public CacheAsmMethodBoost(Class serviceType) {
|
||||||
this.serviceType = serviceType;
|
super(serviceType);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -50,123 +43,38 @@ public class CacheAsmMethodBoost implements AsmMethodBoost {
|
|||||||
if (cached == null) {
|
if (cached == null) {
|
||||||
return newMethodName;
|
return newMethodName;
|
||||||
}
|
}
|
||||||
|
if (method.getAnnotation(DynForCache.class) != null) {
|
||||||
|
return newMethodName;
|
||||||
|
}
|
||||||
if (Modifier.isFinal(method.getModifiers()) || Modifier.isStatic(method.getModifiers())) {
|
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);
|
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())) {
|
if (!Modifier.isProtected(method.getModifiers()) && !Modifier.isPublic(method.getModifiers())) {
|
||||||
throw new RedkaleException("@" + Cached.class.getSimpleName() + " must on protected or public method, but on " + method);
|
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() + "_afterCache";
|
final String rsMethodName = method.getName() + "_afterCache";
|
||||||
final String dynFieldName = fieldPrefix + "_" + method.getName() + "CacheAction" + fieldIndex.incrementAndGet();
|
final String dynFieldName = fieldPrefix + "_" + method.getName() + "CacheAction" + fieldIndex.incrementAndGet();
|
||||||
{
|
{ //定义一个新方法调用 this.rsMethodName
|
||||||
Map<String, AsmMethodBean> methodBeans = AsmMethodBoost.getMethodBeans(serviceType);
|
final AsmMethodBean methodBean = getMethodBean(method);
|
||||||
AsmMethodBean methodBean = AsmMethodBean.get(methodBeans, method);
|
|
||||||
|
|
||||||
final String cacheDynDesc = Type.getDescriptor(DynForCache.class);
|
final String cacheDynDesc = Type.getDescriptor(DynForCache.class);
|
||||||
MethodDebugVisitor mv;
|
final MethodVisitor mv = createMethodVisitor(cw, method, newMethodName, methodBean);
|
||||||
AnnotationVisitor av;
|
|
||||||
String signature = null;
|
|
||||||
String[] exceptions = null;
|
|
||||||
if (methodBean == null) {
|
|
||||||
Class<?>[] expTypes = method.getExceptionTypes();
|
|
||||||
if (expTypes.length > 0) {
|
|
||||||
exceptions = new String[expTypes.length];
|
|
||||||
for (int i = 0; i < expTypes.length; i++) {
|
|
||||||
exceptions[i] = expTypes[i].getName().replace('.', '/');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
signature = methodBean.getSignature();
|
|
||||||
exceptions = methodBean.getExceptions();
|
|
||||||
}
|
|
||||||
//需要定义一个新方法调用 this.rsMethodName
|
|
||||||
mv = new MethodDebugVisitor(cw.visitMethod(acc, nowMethodName, Type.getMethodDescriptor(method), signature, exceptions));
|
|
||||||
//mv.setDebug(true);
|
//mv.setDebug(true);
|
||||||
Label l0 = new Label();
|
Label l0 = new Label();
|
||||||
mv.visitLabel(l0);
|
mv.visitLabel(l0);
|
||||||
av = mv.visitAnnotation(cacheDynDesc, true);
|
AnnotationVisitor av = mv.visitAnnotation(cacheDynDesc, true);
|
||||||
av.visit("dynField", dynFieldName);
|
av.visit("dynField", dynFieldName);
|
||||||
Asms.visitAnnotation(av, cached);
|
Asms.visitAnnotation(av, cached);
|
||||||
if (newMethodName == null) {
|
visitRawAnnotation(method, newMethodName, mv, Cached.class, filterAnns);
|
||||||
//给方法加上原有的Annotation
|
|
||||||
final Annotation[] anns = method.getAnnotations();
|
|
||||||
for (Annotation ann : anns) {
|
|
||||||
if (ann.annotationType() != Cached.class
|
|
||||||
&& (filterAnns == null || !filterAnns.contains(ann.annotationType()))) {
|
|
||||||
Asms.visitAnnotation(mv.visitAnnotation(Type.getDescriptor(ann.annotationType()), true), ann);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
//给参数加上原有的Annotation
|
|
||||||
final Annotation[][] annss = method.getParameterAnnotations();
|
|
||||||
for (int k = 0; k < annss.length; k++) {
|
|
||||||
for (Annotation ann : annss[k]) {
|
|
||||||
Asms.visitAnnotation(mv.visitParameterAnnotation(k, Type.getDescriptor(ann.annotationType()), true), ann);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
mv.visitVarInsn(ALOAD, 0);
|
mv.visitVarInsn(ALOAD, 0);
|
||||||
//传参数
|
//传参数
|
||||||
Class[] paramTypes = method.getParameterTypes();
|
List<Integer> insns = visitVarInsnParamTypes(mv, method);
|
||||||
List<Integer> insns = new ArrayList<>();
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
insns.add(insn);
|
|
||||||
}
|
|
||||||
mv.visitMethodInsn(INVOKESPECIAL, newDynName, rsMethodName, Type.getMethodDescriptor(method), false);
|
mv.visitMethodInsn(INVOKESPECIAL, newDynName, rsMethodName, Type.getMethodDescriptor(method), false);
|
||||||
if (method.getGenericReturnType() == void.class) {
|
visitInsnReturn(mv, method, l0, insns, methodBean);
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (methodBean != null && paramTypes.length > 0) {
|
|
||||||
Label l2 = new Label();
|
|
||||||
mv.visitLabel(l2);
|
|
||||||
//mv.visitLocalVariable("this", thisClassDesc, null, l0, l2, 0);
|
|
||||||
List<String> fieldNames = methodBean.getFieldNames();
|
|
||||||
for (int i = 0; i < paramTypes.length; i++) {
|
|
||||||
mv.visitLocalVariable(fieldNames.get(i), Type.getDescriptor(paramTypes[i]), null, l0, l2, insns.get(i));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
mv.visitMaxs(20, 20);
|
mv.visitMaxs(20, 20);
|
||||||
mv.visitEnd();
|
mv.visitEnd();
|
||||||
}
|
}
|
||||||
{
|
{ //定义字段
|
||||||
FieldVisitor fv = cw.visitField(ACC_PRIVATE, dynFieldName, Type.getDescriptor(CacheAction.class), null, null);
|
FieldVisitor fv = cw.visitField(ACC_PRIVATE, dynFieldName, Type.getDescriptor(CacheAction.class), null, null);
|
||||||
fv.visitEnd();
|
fv.visitEnd();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,17 +6,14 @@ package org.redkale.lock.spi;
|
|||||||
import java.lang.annotation.Annotation;
|
import java.lang.annotation.Annotation;
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
import java.lang.reflect.Modifier;
|
import java.lang.reflect.Modifier;
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
|
||||||
import java.util.concurrent.atomic.AtomicInteger;
|
|
||||||
import org.redkale.asm.AnnotationVisitor;
|
import org.redkale.asm.AnnotationVisitor;
|
||||||
import org.redkale.asm.AsmMethodBean;
|
import org.redkale.asm.AsmMethodBean;
|
||||||
import org.redkale.asm.AsmMethodBoost;
|
import org.redkale.asm.AsmMethodBoost;
|
||||||
import org.redkale.asm.Asms;
|
import org.redkale.asm.Asms;
|
||||||
import org.redkale.asm.ClassWriter;
|
import org.redkale.asm.ClassWriter;
|
||||||
import org.redkale.asm.Label;
|
import org.redkale.asm.Label;
|
||||||
import org.redkale.asm.MethodDebugVisitor;
|
import org.redkale.asm.MethodVisitor;
|
||||||
import static org.redkale.asm.Opcodes.*;
|
import static org.redkale.asm.Opcodes.*;
|
||||||
import org.redkale.asm.Type;
|
import org.redkale.asm.Type;
|
||||||
import org.redkale.lock.Locked;
|
import org.redkale.lock.Locked;
|
||||||
@@ -26,16 +23,12 @@ import org.redkale.util.RedkaleException;
|
|||||||
*
|
*
|
||||||
* @author zhangjx
|
* @author zhangjx
|
||||||
*/
|
*/
|
||||||
public class LockAsmMethodBoost implements AsmMethodBoost {
|
public class LockAsmMethodBoost extends AsmMethodBoost {
|
||||||
|
|
||||||
private static final List<Class<? extends Annotation>> FILTER_ANN = List.of(Locked.class, DynForLock.class);
|
private static final List<Class<? extends Annotation>> FILTER_ANN = List.of(Locked.class, DynForLock.class);
|
||||||
|
|
||||||
private final AtomicInteger fieldIndex = new AtomicInteger();
|
|
||||||
|
|
||||||
protected final Class serviceType;
|
|
||||||
|
|
||||||
public LockAsmMethodBoost(Class serviceType) {
|
public LockAsmMethodBoost(Class serviceType) {
|
||||||
this.serviceType = serviceType;
|
super(serviceType);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -45,8 +38,11 @@ public class LockAsmMethodBoost implements AsmMethodBoost {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String doMethod(ClassWriter cw, String newDynName, String fieldPrefix, List filterAnns, Method method, final String newMethodName) {
|
public String doMethod(ClassWriter cw, String newDynName, String fieldPrefix, List filterAnns, Method method, final String newMethodName) {
|
||||||
Locked cached = method.getAnnotation(Locked.class);
|
Locked locked = method.getAnnotation(Locked.class);
|
||||||
if (cached == null) {
|
if (locked == null) {
|
||||||
|
return newMethodName;
|
||||||
|
}
|
||||||
|
if (method.getAnnotation(DynForLock.class) != null) {
|
||||||
return newMethodName;
|
return newMethodName;
|
||||||
}
|
}
|
||||||
if (Modifier.isFinal(method.getModifiers()) || Modifier.isStatic(method.getModifiers())) {
|
if (Modifier.isFinal(method.getModifiers()) || Modifier.isStatic(method.getModifiers())) {
|
||||||
@@ -55,114 +51,24 @@ public class LockAsmMethodBoost implements AsmMethodBoost {
|
|||||||
if (!Modifier.isProtected(method.getModifiers()) && !Modifier.isPublic(method.getModifiers())) {
|
if (!Modifier.isProtected(method.getModifiers()) && !Modifier.isPublic(method.getModifiers())) {
|
||||||
throw new RedkaleException("@" + Locked.class.getSimpleName() + " must on protected or public method, but on " + method);
|
throw new RedkaleException("@" + Locked.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() + "_afterLock";
|
final String rsMethodName = method.getName() + "_afterLock";
|
||||||
final String dynFieldName = fieldPrefix + "_" + method.getName() + "LockAction" + fieldIndex.incrementAndGet();
|
final String dynFieldName = fieldPrefix + "_" + method.getName() + "LockAction" + fieldIndex.incrementAndGet();
|
||||||
{
|
{ //定义一个新方法调用 this.rsMethodName
|
||||||
Map<String, AsmMethodBean> methodBeans = AsmMethodBoost.getMethodBeans(serviceType);
|
final AsmMethodBean methodBean = getMethodBean(method);
|
||||||
AsmMethodBean methodBean = AsmMethodBean.get(methodBeans, method);
|
|
||||||
|
|
||||||
final String lockDynDesc = Type.getDescriptor(DynForLock.class);
|
final String lockDynDesc = Type.getDescriptor(DynForLock.class);
|
||||||
MethodDebugVisitor mv;
|
final MethodVisitor mv = createMethodVisitor(cw, method, newMethodName, methodBean);
|
||||||
AnnotationVisitor av;
|
|
||||||
String signature = null;
|
|
||||||
String[] exceptions = null;
|
|
||||||
if (methodBean == null) {
|
|
||||||
Class<?>[] expTypes = method.getExceptionTypes();
|
|
||||||
if (expTypes.length > 0) {
|
|
||||||
exceptions = new String[expTypes.length];
|
|
||||||
for (int i = 0; i < expTypes.length; i++) {
|
|
||||||
exceptions[i] = expTypes[i].getName().replace('.', '/');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
signature = methodBean.getSignature();
|
|
||||||
exceptions = methodBean.getExceptions();
|
|
||||||
}
|
|
||||||
//需要定义一个新方法调用 this.rsMethodName
|
|
||||||
mv = new MethodDebugVisitor(cw.visitMethod(acc, nowMethodName, Type.getMethodDescriptor(method), signature, exceptions));
|
|
||||||
//mv.setDebug(true);
|
//mv.setDebug(true);
|
||||||
Label l0 = new Label();
|
Label l0 = new Label();
|
||||||
mv.visitLabel(l0);
|
mv.visitLabel(l0);
|
||||||
av = mv.visitAnnotation(lockDynDesc, true);
|
AnnotationVisitor av = mv.visitAnnotation(lockDynDesc, true);
|
||||||
av.visit("dynField", dynFieldName);
|
av.visit("dynField", dynFieldName);
|
||||||
Asms.visitAnnotation(av, cached);
|
Asms.visitAnnotation(av, locked);
|
||||||
if (newMethodName == null) {
|
visitRawAnnotation(method, newMethodName, mv, Locked.class, filterAnns);
|
||||||
//给方法加上原有的Annotation
|
|
||||||
final Annotation[] anns = method.getAnnotations();
|
|
||||||
for (Annotation ann : anns) {
|
|
||||||
if (ann.annotationType() != Locked.class
|
|
||||||
&& (filterAnns == null || !filterAnns.contains(ann.annotationType()))) {
|
|
||||||
Asms.visitAnnotation(mv.visitAnnotation(Type.getDescriptor(ann.annotationType()), true), ann);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
//给参数加上原有的Annotation
|
|
||||||
final Annotation[][] annss = method.getParameterAnnotations();
|
|
||||||
for (int k = 0; k < annss.length; k++) {
|
|
||||||
for (Annotation ann : annss[k]) {
|
|
||||||
Asms.visitAnnotation(mv.visitParameterAnnotation(k, Type.getDescriptor(ann.annotationType()), true), ann);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
mv.visitVarInsn(ALOAD, 0);
|
mv.visitVarInsn(ALOAD, 0);
|
||||||
//传参数
|
List<Integer> insns = visitVarInsnParamTypes(mv, method);
|
||||||
Class[] paramTypes = method.getParameterTypes();
|
|
||||||
List<Integer> insns = new ArrayList<>();
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
insns.add(insn);
|
|
||||||
}
|
|
||||||
mv.visitMethodInsn(INVOKESPECIAL, newDynName, rsMethodName, Type.getMethodDescriptor(method), false);
|
mv.visitMethodInsn(INVOKESPECIAL, newDynName, rsMethodName, Type.getMethodDescriptor(method), false);
|
||||||
if (method.getGenericReturnType() == void.class) {
|
visitInsnReturn(mv, method, l0, insns, methodBean);
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (methodBean != null && paramTypes.length > 0) {
|
|
||||||
Label l2 = new Label();
|
|
||||||
mv.visitLabel(l2);
|
|
||||||
//mv.visitLocalVariable("this", thisClassDesc, null, l0, l2, 0);
|
|
||||||
List<String> fieldNames = methodBean.getFieldNames();
|
|
||||||
for (int i = 0; i < paramTypes.length; i++) {
|
|
||||||
mv.visitLocalVariable(fieldNames.get(i), Type.getDescriptor(paramTypes[i]), null, l0, l2, insns.get(i));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
mv.visitMaxs(20, 20);
|
mv.visitMaxs(20, 20);
|
||||||
mv.visitEnd();
|
mv.visitEnd();
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user