AOP静态生成Java proxy
静态AOP基于java agent方式加载
java-javaagent:myagent.jar
动态AOP是通过java动态代理或者字节码增强技术在runtime期间进行增强。
静态AOP在这儿定义为在应用启动完成之前,就通过字节码生成技术对代码进行增加。
缺点:动态AOP对原生不能aop ,且遇到USER user = new USER(),user.test()这种方法时无法对其test在不更改代码时进行拦截,静态AOP是可以这样做到。
通常,生成字节码技术的方式有两种,一种类于javaproxy产生的字节码样式(1)。一种是在进入方法和限出方法时注入代码实现aop代码增强(2)。
接下来,我们来讲一下具体实现
首先第一步,需要写一个启动类premain方法
public static void premain(String agentArgs, Instrumentation inst) {
// 这儿实现对代码的字节码增强 }
第二步
实现第一种生成aop-proxy-interceptor的方式核心代码
EffectiveAopMaker类是入口类:
import com.tmall.tmpp.tools.aop.MethodInfo; import com.tmall.tmpp.tools.extension.*; import org.objectweb.asm.ClassReader; import org.objectweb.asm.ClassVisitor; import org.objectweb.asm.ClassWriter; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.InputStream; import java.util.ArrayList; import java.util.List; /** * 通过class新增字段和方法提升性能的aop方式 */ public class EffectiveAopMaker implements AopMaker { public byte[] createInterceptorCodes(String targetClazz, List<MethodInfo> cepMethods, InvocationInterceptor interceptor , ClassLoader targetClassLoader, byte[] classToTransfer) throws Exception { try { return createInterceptorCodes(targetClazz, cepMethods, interceptor, targetClassLoader, classToTransfer, true); } catch (Exception e) { System.out.println("[asm-aop]COMPUTE_FRAMES,try use COMPUTE_MAXS instead!"); try { return createInterceptorCodes(targetClazz, cepMethods, interceptor, targetClassLoader, classToTransfer, false); } catch (Exception e1) { System.out.println("[asm-aop]COMPUTE_MAX error!"); e1.printStackTrace(); throw e1; } } } public byte[] createInterceptorCodes(String targetClazz, List<MethodInfo> cepMethods, InvocationInterceptor interceptor , ClassLoader targetClassLoader, byte[] classToTransfer, boolean isUseComputeFrame) throws Exception { ByteArrayInputStream inputStream = new ByteArrayInputStream(classToTransfer); ClassReader cr = new ClassReader(inputStream); int flag = ClassWriter.COMPUTE_MAXS; if (isUseComputeFrame) { flag |= ClassWriter.COMPUTE_FRAMES; } ClassWriter classWriter = new EasyClassWriter(flag); ClassVisitor classVisitor = new EffectiveClassAdaptor(classWriter, cepMethods, interceptor, targetClazz); cr.accept(classVisitor, ClassReader.EXPAND_FRAMES); AopParameter aopParameter = new AopParameter(); aopParameter.setInvocationInterceptor(interceptor); List<CepMethod> methods = new ArrayList<CepMethod>(); for (MethodInfo methodInfo : cepMethods) { CepMethod cepMethod = new CepMethod(targetClazz); cepMethod.setParamClassNames(methodInfo.getParamClassNames()); cepMethod.setSubName(methodInfo.getSubMethodName()); methods.add(cepMethod); } aopParameter.setCepMethods(methods); AopContext.addAopParameter(targetClassLoader, targetClazz, aopParameter); byte[] classBytes = classWriter.toByteArray(); String[] arr = targetClazz.split("\\."); String savedFileName = arr[arr.length - 1] + ".class"; CommonUtils.writeByteToFile(savedFileName, classBytes); return classBytes; } private byte[] createInterceptorCodes(String targetClazz, List<MethodInfo> cepMethods, InvocationInterceptor interceptor, ClassLoader targetClassLoader, ResourceResolver resourceResolver) throws Exception { String classFile = AsmClassUtil.forPath(targetClazz); InputStream inputStream = null; if (resourceResolver != null) { ResourceInfo resourceInfo = resourceResolver.loadStream(classFile); if (resourceInfo != null) { inputStream = resourceInfo.getInputStream(); } } else { inputStream = targetClassLoader.getResourceAsStream(classFile); } if (inputStream == null) { throw new RuntimeException("resource not found!" + targetClazz); } ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); int i = 0; while ((i = inputStream.read()) != -1) { outputStream.write(i); } return createInterceptorCodes(targetClazz, cepMethods, interceptor, targetClassLoader, outputStream.toByteArray()); } public Class<?> intercept(final String targetClazz, final List<MethodInfo> cepMethods, final InvocationInterceptor interceptor, ClassLoader targetClassLoader, ResourceResolver resourceResolver) throws Exception { if (targetClassLoader == null) { targetClassLoader = EffectiveAopMaker.class.getClassLoader(); } final byte[] codes = createInterceptorCodes(targetClazz, cepMethods, interceptor, targetClassLoader, resourceResolver); //如果是classNotFound导致的加载失败则重试 AsmClassUtil.safelyExecute(targetClassLoader, resourceResolver, new SafeExecute() { public void execute(ClassLoader loader, ResourceResolver resolver) throws Exception { AsmClassUtil.reload(codes, targetClazz, loader); } }); final Class<?> clazz = Class.forName(targetClazz, false, targetClassLoader); return clazz; } }
EffectiveClassAdaptor类是字节码增强类的代码,通过asm的classvisiter时生成,代码如下:
** * todo * 1. 返回是原始类型的场景 * 2. 返回和入参是void的场景 * <p/> * 实现方案: * 将被aop的方法重命名,生成同名代理方法,插入aop逻辑。 * 给每个被aop的方法对应的class Method设置静态变量保存以免调用时去查找field提高性能 */
public class EffectiveClassAdaptor extends ClassVisitor implements Opcodes { Set<String> existFieldSet = new HashSet<String>(); Set<String> existMethodSet = new HashSet<String>(); InvocationInterceptor invocationInterceptor; private boolean isInterface; List<MethodInfo> methodInfoList; Map<String, MethodInfo> methodIndex = new HashMap<String, MethodInfo>(); String targetClassName; private String srcClassName; private Set<String> innerClassSet = new HashSet<String>(); private Map<String, MethodDetail> methodDetailMap = new HashMap<String, MethodDetail>(); public EffectiveClassAdaptor(ClassVisitor classVisitor, List<MethodInfo> methodList, InvocationInterceptor invocationInterceptor, String targetClassName) throws ClassNotFoundException { super(AsmAop.ASM_VERSION, classVisitor); this.methodInfoList = methodList; for (MethodInfo methodInfo : methodList) { methodIndex.put(methodInfo.getCode(), methodInfo); } this.invocationInterceptor = invocationInterceptor; this.srcClassName = targetClassName.replaceAll("\\.", "/"); this.targetClassName = srcClassName; } @Override public void visitInnerClass(String s, String s2, String s3, int i) { innerClassSet.add(s); super.visitInnerClass(s, s2, s3, i); } @Override public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) { isInterface = (access & ACC_INTERFACE) != 0; //要49版本以上的class才支持ldc_w out.println("class version" + version + " 49@" + name); if (version < 49) { out.println("change class version from" + version + "to 49@" + name); version = 49; } super.visit(version, access, name, signature, superName, interfaces); } @Override public FieldVisitor visitField(int access, String name, String desc, String signature, Object value) { existFieldSet.add(name); //out.println("visitField->" + name + ":" + desc + ":" + signature); if (name.equals(targetClassName)) { return super.visitField(access, name + "_Proxy", desc, signature, value); } else { return super.visitField(access, name, desc, signature, value); } } @Override public void visitSource(String s, String s2) { //out.println("visitSource->" + s + ":" + s2); super.visitSource(s, s2); } @Override public void visitAttribute(Attribute attribute) { super.visitAttribute(attribute); } public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) { existMethodSet.add(name); String newName = name; MethodInfo methodInfo = methodIndex.get(name + "_" + desc); MethodDetail m = new MethodDetail(); m.access = access; m.desc = desc; m.exceptions = exceptions; m.signature = signature; m.name = name; if (methodInfo != null) { newName = methodInfo.getSubMethodName(); methodDetailMap.put(methodInfo.getCode(), m); } MethodVisitor mv = super.visitMethod(access, newName, desc, signature, exceptions); if (methodInfo != null) { return new MethodDetailVisitor(mv, m); } else { return mv; } } @Override public void visitEnd() { //out.println("InvocationInterceptorV1:" + Type.getDescriptor(InvocationInterceptor.class)); if (!existFieldSet.contains(AopContext.PROXY_INTERCEPTOR)) { FieldVisitor fv = super.visitField(Opcodes.ACC_STATIC + Opcodes.ACC_PUBLIC, AopContext.PROXY_INTERCEPTOR, Type.getDescriptor(InvocationInterceptor.class), null, null); if (fv != null) { super.visitEnd(); } } for (MethodInfo methodInfo : methodInfoList) { if (!existFieldSet.contains(methodInfo.getSubMethodName())) { FieldVisitor fv = super.visitField(Opcodes.ACC_STATIC + Opcodes.ACC_PUBLIC, methodInfo.getSubMethodName(), Type.getDescriptor(Method.class), null, null); if (fv != null) { super.visitEnd(); } } } if (!isInterface) { try { for (MethodInfo methodInfo : methodInfoList) { if (!existMethodSet.contains(methodInfo.getSubMethodName())) { //String descriptor = Type.getMethodDescriptor(methodInfo.getAsmReturnType(), methodInfo.getAsmParameterTypes()); //out.println("descriptor" + descriptor); MethodDetail methodDef = methodDetailMap.get(methodInfo.getCode()); MethodVisitor mvOrigin = super.visitMethod(methodDef.access, methodDef.name, methodDef.desc, methodDef.signature, methodDef.exceptions); //to solve 'JSR/RET are not supported with computeFrames option' problem JSRInlinerAdapter mv = new JSRInlinerAdapter(mvOrigin, methodDef.access, methodDef.name, methodDef.desc, methodDef.signature, methodDef.exceptions); //annotation List<MethodDetail.Annotation> annotations = methodDef.getAnnotations(); if (annotations != null) { for (MethodDetail.Annotation annotation : annotations) { AnnotationVisitor visitor = mv.visitAnnotation(annotation.getDesc(), annotation.isVisible()); annotation.getAnnotationNode().accept(visitor); } } //参数注解 List<MethodDetail.MethodAnnotation> methodAnnotations = methodDef.getMethodAnnotations(); if (methodAnnotations != null) { for (MethodDetail.MethodAnnotation methodAnnotation : methodAnnotations) { AnnotationVisitor visitor = mv.visitParameterAnnotation(methodAnnotation.getParameter(), methodAnnotation.getDesc(), methodAnnotation.isVisible()); methodAnnotation.getAnnotationNode().accept(visitor); } } List<MethodDetail.TypeLsnAnnotation> typeAnnotations = methodDef.getTypeAnnotations(); if (typeAnnotations != null) { for (MethodDetail.TypeLsnAnnotation typeAnnotation : typeAnnotations) { AnnotationVisitor visitor = mv.visitTypeAnnotation(typeAnnotation.getTypeRef(), typeAnnotation.getTypePath(), typeAnnotation.getDesc(), typeAnnotation.isVisible()); typeAnnotation.getAnnotationNode().accept(visitor); } } List<MethodDetail.TypeLsnAnnotation> lsnAnnotations = methodDef.getLsnAnnotations(); if (lsnAnnotations != null) { for (MethodDetail.TypeLsnAnnotation lsnAnnotation : lsnAnnotations) { AnnotationVisitor visitor = mv.visitInsnAnnotation(lsnAnnotation.getTypeRef(), lsnAnnotation.getTypePath(), lsnAnnotation.getDesc(), lsnAnnotation.isVisible()); lsnAnnotation.getAnnotationNode().accept(visitor); } } List<MethodDetail.Annotation> defAnnotations = methodDef.getDefaultAnnotations(); if (defAnnotations != null) { for (MethodDetail.Annotation annotation : defAnnotations) { AnnotationVisitor visitor = mv.visitAnnotationDefault(); annotation.getAnnotationNode().accept(visitor); } } mv.visitCode(); //----------------构造参数 boolean isStaticMethod = ((methodDef.access & Opcodes.ACC_STATIC) != 0); //创建数组 int paramCount = methodInfo.getAsmParameterTypes().length; int curLocalVarIdx = isStaticMethod ? 0 : 1; if (paramCount > 0) { if (paramCount <= 5) { mv.visitInsn(ICONST_0 + paramCount); } else { mv.visitVarInsn(BIPUSH, paramCount); } mv.visitTypeInsn(Opcodes.ANEWARRAY, "java/lang/Object"); Type[] paramTypes = methodInfo.getAsmParameterTypes(); for (int i = 0; i < paramTypes.length; i++) { Type type = paramTypes[i]; mv.visitInsn(DUP); if (i <= 5) { mv.visitInsn(ICONST_0 + i); } else { mv.visitVarInsn(BIPUSH, i); } //变量入栈,并返回移动步长 int moveIndex = AsmClassUtil.pushVarInStackWithBox(mv, curLocalVarIdx, type); curLocalVarIdx += moveIndex; //stackSize += moveIndex; mv.visitInsn(Opcodes.AASTORE); } } else { mv.visitInsn(ICONST_0); mv.visitTypeInsn(Opcodes.ANEWARRAY, "java/lang/Object"); } //保存数组 int arrIdx = curLocalVarIdx; mv.visitVarInsn(Opcodes.ASTORE, arrIdx); curLocalVarIdx++; String interceptorClass = InvocationInterceptor.class.getName().replaceAll("\\.", "/"); //执行初始化前判断 mv.visitFieldInsn(GETSTATIC, targetClassName, AopContext.PROXY_INTERCEPTOR, String.format("L%s;", interceptorClass)); Label label = new Label(); mv.visitJumpInsn(IFNONNULL, label);//LDC_W, targetClassName mv.visitLdcInsn(Type.getType(String.format("L%s;", targetClassName))); mv.visitMethodInsn(INVOKESTATIC, AopContext.class.getName().replace(".", "/"), "initAopParameter", "(Ljava/lang/Class;)V", false); mv.visitLabel(label); mv.visitFrame(F_NEW, 1, new String[]{interceptorClass}, 1, new String[]{interceptorClass}); //调用注入的方法 mv.visitFieldInsn(GETSTATIC, targetClassName, AopContext.PROXY_INTERCEPTOR, String.format("L%s;", interceptorClass)); if (isStaticMethod) { mv.visitInsn(ACONST_NULL); } else { mv.visitVarInsn(ALOAD, 0); } mv.visitFieldInsn(GETSTATIC, targetClassName, methodInfo.getSubMethodName(), "Ljava/lang/reflect/Method;"); mv.visitVarInsn(ALOAD, arrIdx); mv.visitMethodInsn(INVOKEINTERFACE, interceptorClass, "invoke", "(Ljava/lang/Object;Ljava/lang/reflect/Method;[Ljava/lang/Object;)Ljava/lang/Object;", true); if (methodInfo.getAsmReturnType() != Type.VOID_TYPE) { AsmClassUtil.convertAndReturn(mv, methodInfo.getAsmReturnType()); } else { mv.visitInsn(Opcodes.POP); mv.visitInsn(RETURN); } mv.visitMaxs(0, 0); mv.visitEnd(); super.visitEnd(); } } } catch (Exception e) { e.printStackTrace(); } } super.visitEnd(); ] }
其中end方法是真正生成代码的地方。
其他相关类:AopContext:
public class AopContext { public static final String PROXY_INTERCEPTOR = "interceptor_$"; private static Map<String, AopParameter> aopParameterMap = new ConcurrentHashMap(); public AopContext() { } public static void initAopParameter(Class<?> clazz) { synchronized(clazz) { try { Field e = clazz.getDeclaredField("interceptor_$"); if(!e.isAccessible()) { e.setAccessible(true); } Object val = e.get((Object)null); if(val != null) { return; } AopParameter aopParameter = getAopParameter(clazz.getClassLoader(), clazz.getName()); CepMethod methodInfo; String methodName; Field subMethod; for(Iterator i$ = aopParameter.getCepMethods().iterator(); i$.hasNext(); subMethod.set((Object)null, clazz.getDeclaredMethod(methodName, methodInfo.getParamTypes()))) { methodInfo = (CepMethod)i$.next(); methodInfo.init(clazz.getClassLoader()); methodName = methodInfo.getSubName(); subMethod = clazz.getField(methodInfo.getSubName()); if(!subMethod.isAccessible()) { subMethod.setAccessible(true); } } } catch (Exception var10) { var10.printStackTrace(); } } } public static void addAopParameter(ClassLoader classLoader, String className, AopParameter aopParameter) { aopParameterMap.put(classLoader == null?"":classLoader.toString() + className, aopParameter); aopParameterMap.put(className, aopParameter); } public static AopParameter getAopParameter(ClassLoader classLoader, String className) { AopParameter aopParameter = (AopParameter)aopParameterMap.get(classLoader == null?"":classLoader.toString() + className); if(aopParameter == null) { aopParameter = (AopParameter)aopParameterMap.get(className); } return aopParameter; } }
MethodDetail 为拦截方法的描述类
public class MethodDetail { public static class Annotation { private String desc; private boolean visible; private AnnotationNode annotationNode; public Annotation(String desc, boolean visible) { this.desc = desc; this.visible = visible; } public AnnotationNode getNode() { if (annotationNode == null) { annotationNode = new AnnotationNode(desc); } return annotationNode; } public String getDesc() { return desc; } public boolean isVisible() { return visible; } public AnnotationNode getAnnotationNode() { return annotationNode; } public void setAnnotationNode(AnnotationNode annotationNode) { this.annotationNode = annotationNode; } } public static class MethodAnnotation extends Annotation { private int parameter; public MethodAnnotation(int parameter, String desc, boolean visible) { super(desc, visible); this.parameter = parameter; } public int getParameter() { return parameter; } } public static class TypeLsnAnnotation extends Annotation { private int typeRef; private TypePath typePath; public TypeLsnAnnotation(int typeRef, TypePath typePath, String desc, boolean visible) { super(desc, visible); this.typePath = typePath; this.typeRef = typeRef; } public int getTypeRef() { return typeRef; } public TypePath getTypePath() { return typePath; } } public int access; public String name; public String desc; public String signature; public String[] exceptions; public List<Annotation> annotations; public List<MethodAnnotation> methodAnnotations; public List<Annotation> defaultAnnotations; public List<TypeLsnAnnotation> typeAnnotations; public List<TypeLsnAnnotation> lsnAnnotations; // public List<LineNumberItem> lineNumberItems; public void addAnnotation(Annotation annotation) { if (annotations == null) { annotations = new ArrayList<Annotation>(); } annotations.add(annotation); } public void addMethodAnnotation(MethodAnnotation methodAnnotation) { if (methodAnnotations == null) { methodAnnotations = new ArrayList<MethodAnnotation>(); } methodAnnotations.add(methodAnnotation); } public void addDefaultAnnotation(Annotation annotation) { if (defaultAnnotations == null) { defaultAnnotations = new ArrayList<Annotation>(); } defaultAnnotations.add(annotation); } public void addTypeAnnotation(TypeLsnAnnotation typeAnnotation) { if (typeAnnotations == null) { typeAnnotations = new ArrayList<TypeLsnAnnotation>(); } typeAnnotations.add(typeAnnotation); } public void addLsnAnnotation(TypeLsnAnnotation lsnAnnotation) { if (lsnAnnotations == null) { lsnAnnotations = new ArrayList<TypeLsnAnnotation>(); } lsnAnnotations.add(lsnAnnotation); } public List<Annotation> getAnnotations() { return annotations; } public List<MethodAnnotation> getMethodAnnotations() { return methodAnnotations; } public List<TypeLsnAnnotation> getTypeAnnotations() { return typeAnnotations; } public List<TypeLsnAnnotation> getLsnAnnotations() { return lsnAnnotations; } public List<Annotation> getDefaultAnnotations() { return defaultAnnotations; } }
///asm执行时的工具类:
public classAsmClassUtil {
private static MethoddefineClass1,defineClass2;
private static Method definePackage;
private static Unsafe unSafe;
static {
try {
AccessController.doPrivileged(newPrivilegedExceptionAction() {
public Objectrun()throws Exception {
Class cl = Class.forName("java.lang.ClassLoader");
defineClass1 = cl.getDeclaredMethod("defineClass",
new Class[]{String.class, byte[].class,
int.class, int.class});
defineClass2 = cl.getDeclaredMethod("defineClass",
new Class[]{String.class, byte[].class,
int.class, int.class,ProtectionDomain.class});
definePackage = cl.getDeclaredMethod("definePackage",
new Class[]{String.class,String.class,String.class,
String.class,String.class,String.class,
String.class,java.net.URL.class});
Field f = Unsafe.class.getDeclaredField("theUnsafe");// Internal reference
f.setAccessible(true);
unSafe = (Unsafe) f.get(null);
return null;
}
});
} catch(PrivilegedActionException pae) {
throw new RuntimeException("cannot initialize ClassPool",pae.getException());
}
}
public static Classreload(byte[] b,String clazz,ClassLoaderclassLoader)throwsException {
Object domain = null;
if (classLoader == null) {
classLoader = Thread.currentThread().getContextClassLoader();
}
try {
Method method;
Object[] args;
if (domain == null) {
method = defineClass1;
args = newObject[]{clazz,b, newInteger(0),
new Integer(b.length)};
} else{
method = defineClass2;
args = newObject[]{clazz,b, newInteger(0),
new Integer(b.length),domain};
}
System.out.println("loaded "+ clazz +" to "+ classLoader.getClass().getName() +"@" + classLoader);
return (Class) toClass2(method,classLoader,args);
} catch(RuntimeException e) {
throw e;
}
}
private static synchronized ObjecttoClass2(Method method,
ClassLoader loader,Object[] args)
throws Exception {
method.setAccessible(true);
try {
return method.invoke(loader,args);
} finally{
method.setAccessible(false);
}
}
public static int pushVarInStackWithBox(MethodVisitor mv, inti,Type type) {
if (type !=null&& type.getSort() >=0&& type.getSort() <=8) {
if (type == Type.INT_TYPE) {
mv.visitIntInsn(Opcodes.ILOAD,i);
mv.visitMethodInsn(Opcodes.INVOKESTATIC,"java/lang/Integer","valueOf","(I)Ljava/lang/Integer;");
return 1;
} else if(type == Type.CHAR_TYPE) {
mv.visitIntInsn(Opcodes.ILOAD,i);
mv.visitMethodInsn(Opcodes.INVOKESTATIC,"java/lang/Character","valueOf","(C)Ljava/lang/Character;");
return 1;
} else if(type == Type.LONG_TYPE) {
mv.visitIntInsn(Opcodes.LLOAD,i);
mv.visitMethodInsn(Opcodes.INVOKESTATIC,"java/lang/Long","valueOf","(J)Ljava/lang/Long;");
return 2;
} else if(type == Type.FLOAT_TYPE) {
mv.visitIntInsn(Opcodes.FLOAD,i);
mv.visitMethodInsn(Opcodes.INVOKESTATIC,"java/lang/Float","valueOf","(F)Ljava/lang/Float;");
return 1;
} else if(type == Type.DOUBLE_TYPE) {
mv.visitIntInsn(Opcodes.DLOAD,i);
mv.visitMethodInsn(Opcodes.INVOKESTATIC,"java/lang/Double","valueOf","(D)Ljava/lang/Double;");
return 2;
} else if(type == Type.BYTE_TYPE) {
mv.visitIntInsn(Opcodes.ILOAD,i);
mv.visitMethodInsn(Opcodes.INVOKESTATIC,"java/lang/Byte","valueOf","(B)Ljava/lang/Byte;");
return 1;
} else if(type == Type.SHORT_TYPE) {
mv.visitIntInsn(Opcodes.ILOAD,i);
mv.visitMethodInsn(Opcodes.INVOKESTATIC,"java/lang/Short","valueOf","(S)Ljava/lang/Short;");
return 1;
} else if(type == Type.BOOLEAN_TYPE) {
mv.visitIntInsn(Opcodes.ILOAD,i);
mv.visitMethodInsn(Opcodes.INVOKESTATIC,"java/lang/Boolean","valueOf","(Z)Ljava/lang/Boolean;");
return 1;
}
} else {
mv.visitVarInsn(Opcodes.ALOAD,i);
}
return 1;
}
public static int convertAndReturn(MethodVisitor mv,Type type) {
if (type.getSort()>=0&& type.getSort() <=8) {
if (type == Type.INT_TYPE) {
mv.visitTypeInsn(Opcodes.CHECKCAST,"java/lang/Integer");
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL,"java/lang/Integer","intValue","()I");
mv.visitInsn(Opcodes.IRETURN);
return 1;
} else if(type == Type.CHAR_TYPE) {
mv.visitTypeInsn(Opcodes.CHECKCAST,"java/lang/Character");
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL,"java/lang/Character","charValue","()C");
mv.visitInsn(Opcodes.IRETURN);
return 1;
} else if(type == Type.LONG_TYPE) {
mv.visitTypeInsn(Opcodes.CHECKCAST,"java/lang/Long");
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL,"java/lang/Long","longValue","()J");
mv.visitInsn(Opcodes.LRETURN);
return 2;
} else if(type == Type.FLOAT_TYPE) {
mv.visitTypeInsn(Opcodes.CHECKCAST,"java/lang/Float");
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL,"java/lang/Float","floatValue","()F");
mv.visitInsn(Opcodes.FRETURN);
return 1;
} else if(type == Type.DOUBLE_TYPE) {
mv.visitTypeInsn(Opcodes.CHECKCAST,"java/lang/Double");
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL,"java/lang/Double","doubleValue","()D");
mv.visitInsn(Opcodes.DRETURN);
return 2;
} else if(type == Type.BYTE_TYPE) {
mv.visitTypeInsn(Opcodes.CHECKCAST,"java/lang/Byte");
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL,"java/lang/Byte","byteValue","()B");
mv.visitInsn(Opcodes.IRETURN);
return 1;
} else if(type == Type.SHORT_TYPE) {
mv.visitTypeInsn(Opcodes.CHECKCAST,"java/lang/Short");
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL,"java/lang/Short","shortValue","()S");
mv.visitInsn(Opcodes.IRETURN);
return 1;
} else if(type == Type.BOOLEAN_TYPE) {
mv.visitTypeInsn(Opcodes.CHECKCAST,"java/lang/Boolean");
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL,"java/lang/Boolean","booleanValue","()Z");
mv.visitInsn(Opcodes.IRETURN);
return 1;
}
} else {
mv.visitTypeInsn(Opcodes.CHECKCAST,type.getInternalName());
mv.visitInsn(Opcodes.ARETURN);
return 1;
}
return 1;
}
public static class MethodInfoReadAdaptorextendsClassVisitor {
private static final Set<String>baseMethodSet=new HashSet<String>();
/**
* 是否忽略private方法的拦截
*/
private boolean isIgnorePrivate;
/**
* 是否忽略protected方法的拦截
*/
private boolean isIgnoreProtected;
static {
baseMethodSet.add("<init>");
baseMethodSet.add("toString");
baseMethodSet.add("clone");
baseMethodSet.add("hashCode()");
baseMethodSet.add("<clinit>");
}
private List<MethodInfo>methodInfoList=new ArrayList<MethodInfo>();
public MethodInfoReadAdaptor(ClassVisitorclassAdapter, booleanisIgnorePrivate, booleanisIgnoreProtected) {
super(AsmAop.ASM_VERSION,classAdapter);
this.isIgnorePrivate= isIgnorePrivate;
this.isIgnoreProtected= isIgnoreProtected;
}
public boolean hasFlag(intmod, intflag) {
return (mod & flag) !=0;
}
static final int BRIDGE=0x00000040;
static final int SYNTHETIC = 0x00001000;
@Override
public MethodVisitorvisitMethod(intaccess,String name,String desc,Stringsignature,String[] exceptions) {
//排除特殊方法
if (!baseMethodSet.contains(name)&&
!name.contains("jacocoInit")
&&!name.startsWith("$")) {
boolean isSkip =false;
//跳过桥方法
if (hasFlag(access,BRIDGE) ||hasFlag(access,SYNTHETIC)) {
isSkip = true;
}
if ((isIgnorePrivate&& Modifier.isPrivate(access))
|| (isIgnoreProtected && Modifier.isProtected(access))){
isSkip = true;
}
//如果忽略private和 protected,则只有public才拦截
if (isIgnorePrivate&&isIgnoreProtected&& !Modifier.isPublic(access)){
isSkip = true;
}
if (!isSkip) {
Type[] paramTypes =Type.getArgumentTypes(desc);
Type returnType = Type.getReturnType(desc);
StringBuilder sb = new StringBuilder();
sb.append(getConvertedClassName(returnType.getClassName()));
sb.append(" ").append(name).append("(");
List<String> types = new ArrayList<String>();
for (Type type : paramTypes) {
types.add(getConvertedClassName(type.getClassName()));
}
sb.append(StringUtils.join(types,","));
sb.append(")");
MethodInfo methodInfo = new MethodInfo(sb.toString(),desc);
methodInfoList.add(methodInfo);
}
}
return super.visitMethod(access,name,desc, signature,exceptions);
}
public List<MethodInfo>getMethodInfoList() {
return methodInfoList;
}
}
public static List<MethodInfo>readMethodInfoList(InputStream inputStream, booleanisIgnorePrivate, booleanisIgnoreProtected) throwsIOException {
ClassReader cr = new ClassReader(inputStream);
ClassWriter cw = newClassWriter(cr,ClassWriter.COMPUTE_MAXS);
MethodInfoReadAdaptor adaptor = new MethodInfoReadAdaptor(cw,isIgnorePrivate,isIgnoreProtected);
cr.accept(adaptor,ClassWriter.COMPUTE_MAXS);
return adaptor.getMethodInfoList();
}
public static List<MethodInfo>readMethodInfoList(InputStream inputStream)throwsIOException {
return readMethodInfoList(inputStream, false, false);
}
public static StringgetConvertedClassName(StringclassName) {
if (CepMethod.baseTypes.contains(className)) {
return className;
}
return className;
}
public static StringconvertLoadableClassName(Type type) {
if (CepMethod.getBaseType(type.getClassName())!=null) {
return type.getClassName();
}
return type.getInternalName().replace("/",".");
}
public static Class<?>getClassByName(String className, finalClassLoader classLoader) throwsClassNotFoundException{
Class<?> clazz = CepMethod.baseType.get(className);
if (clazz != null) {
return clazz;
}
if (className.indexOf("[][]") >0) {
String subClassName =className.replaceAll("\\[]\\[]","");
Class<?> subClazz = getClassByName(subClassName,classLoader);
if (subClazz.isPrimitive()) {
className = String.format("[[%s",Type.getType(subClazz).getDescriptor());
} else{
className = String.format("[[L%s;",subClazz.getName());
}
} else if (className.indexOf("[]") >0) {
String subClassName = className.replaceAll("\\[]","");
Class<?> subClazz = getClassByName(subClassName,classLoader);
if (subClazz.isPrimitive()) {
className = String.format("[%s",Type.getType(subClazz).getDescriptor());
} else{
className = String.format("[L%s;",subClazz.getName());
}
}
Class<?> typeClass = null;
try {
typeClass = Class.forName(className, false,classLoader);
} catch(ClassNotFoundException e) {
}
if (typeClass ==null) {
throw new ClassNotFoundException(className);
}
return typeClass;
}
public static StringtoClassName(Class<?>clazz) {
if (clazz.isPrimitive()){
return Type.getType(clazz).getClassName();
} else if(clazz.isArray()) {
Class<?> c =clazz.getComponentType();
return toClassName(c) +"[]";
} else{
return clazz.getName();
}
}
/**
* 将class加载到classLoader中
*
* @param inputStream
* @param className
* @param classLoader
* @throws Exception
*/
public static void defineClassFromStream(InputStream inputStream,StringclassName,ClassLoader classLoader) throwsException {
if (inputStream!=null) {
ByteArrayOutputStreamoutputStream = newByteArrayOutputStream();
int b = 0;
try {
while ((b = inputStream.read()) != -1) {
outputStream.write(b);
}
inputStream.close();
} catch(IOException e) {
throw new IllegalStateException("load class "+ className +" error!",e);
}
//exposure to parent
byte[] bytes =outputStream.toByteArray();
reload(bytes,className,classLoader);
System.out.println("loaded"+ className +" to "+ classLoader);
}
}
public static StringforPath(StringclassName) {
return className.replaceAll("\\.","/").concat(".class");
}
public static void safelyExecute(ClassLoader loader,ResourceResolverresolver,SafeExecute executor) throwsException {
boolean isExecuteOk =false;
int deep = 0;
DO_EXECUTE:
while (!isExecuteOk) {
try {
executor.execute(loader, resolver);
isExecuteOk = true;
} catch(Throwable e) {
if (resolver ==null) {
throw new Exception(e);
}
while (e !=null) {
StringmissedClassName = null;
if (e instanceofClassNotFoundException) {
missedClassName =e.getMessage();
}
if (missedClassName !=null) {
missedClassName =missedClassName.trim();
if (missedClassName.startsWith("L") & missedClassName.endsWith(";")) {
missedClassName= missedClassName.substring(1,missedClassName.length() -1);
}
final String missedClassPath = AsmClassUtil.forPath(missedClassName);
System.out.println("-->safelyExecuteretry class is "+missedClassPath + "-->"+ missedClassName);
ResourceInfo resourceInfo =resolver.loadStream(missedClassPath);
if (resourceInfo == null || resourceInfo.getInputStream() ==null) {
System.out.println("-->safelyExecute not find class is "+ missedClassName);
throw new RuntimeException(missedClassName);
}
final String finalMissedClassName = missedClassName;
safelyExecute(loader,resolver, newSafeExecute() {
public void execute(ClassLoader loader,ResourceResolver resolver)throwsException {
InputStream inputStream = resolver.loadStream(missedClassPath).getInputStream();
defineClassFromStream(inputStream,finalMissedClassName,loader);
}
});
System.out.println("-->safelyExecutedefine class success "+ missedClassName);
continue DO_EXECUTE;
} else{
if (e.getCause() ==null) {
e.printStackTrace();
}
if (deep++ >100) {
throw new Exception(e);
}
e = e.getCause();
}
}
}
}
}
public static void checkInit(Class<?> clazz) {
unSafe.ensureClassInitialized(clazz);
}
public static List<MethodInfo>buildMatchedMethod(InjectContext injectContext)throwsException {
String fullClassName =injectContext.getFullClassName();
List<String> patterns = injectContext.getPatterns();
if (fullClassName == null|| fullClassName.trim().isEmpty() || patterns ==null) {
System.out.println("buildMatchedMethod error:"+ fullClassName +"@"+ patterns);
throw new IllegalArgumentException("argument error!");
}
List<MethodInfo>matchedMethods = new ArrayList<MethodInfo>();
String classFile = AsmClassUtil.forPath(fullClassName);
InputStream is = injectContext.getClassLoader().getResourceAsStream(classFile);
if (is == null) {
throw new RuntimeException("class file not found ->"+ fullClassName);
}
//从字节码中读取到类型总的方法
List<MethodInfo> methodInfos = AsmClassUtil.readMethodInfoList(is,injectContext.isIgnorePrivate(),injectContext.isIgnoreProtected());
is.close();
if (methodInfos.isEmpty()) {
return matchedMethods;
}
int idx =0;
List<Pattern> ptns = newArrayList<Pattern>();
List<Pattern> excludePtns = newArrayList<Pattern>();
for (String pattern : patterns) {
Pattern ptn = Pattern.compile(processPattern(pattern));
ptns.add(ptn);
}
if (injectContext.getExcludePatterns()!=null) {
for (String patten : injectContext.getExcludePatterns()) {
excludePtns.add(Pattern.compile(processPattern(patten)));
}
}
//匹配方法
for (MethodInfomethodInfo : methodInfos) {
MATCH:
for (Pattern pattern : ptns) {
Matcher matcher =pattern.matcher(methodInfo.getDescriptorNormal());
if (matcher.matches()) {
//执行排除逻辑
boolean isExclude =false;
EXCLUDE:
for (Pattern ptn : excludePtns) {
MatcherexcludeMatcher = ptn.matcher(methodInfo.getDescriptorNormal());
if (excludeMatcher.matches()) {
isExclude = true;
break EXCLUDE;
}
}
if (!isExclude) {
methodInfo.setIndex(idx++);
matchedMethods.add(methodInfo);
}
break MATCH;
}
}
}
return matchedMethods;
}
private static StringprocessPattern(String ptn) {
ptn = ptn.replaceAll("\\[]","【】");
ptn = ptn.replaceAll("$__[(]","_$_");
ptn = ptn.replaceAll("[*]",".*").replaceAll("[()","[()"].replaceAll("[])","[]]")
.replaceAll("###","(").replaceAll("&&&",")");
ptn = ptn.replaceAll("【】","\\\\[]");
return ptn;
)
public static List<MethodInfo>buildMatchedMethod(String fullClassName,List<String>patterns,ClassLoader classLoader,ResourceResolver resourceResolver)throwsException {
InjectContext injectContext = new InjectContext();
injectContext.setFullClassName(fullClassName);
injectContext.setPatterns(patterns);
injectContext.setClassLoader(classLoader);
return buildMatchedMethod(injectContext);
}
public static StringgetObjectDescriptor(String name){
StringBuilder buf = new StringBuilder();
buf.append('L');
int len = name.length();
for (inti =0;i < len;++i) {
char car = name.charAt(i);
buf.append(car == '.'?'/': car);
}
buf.append(';');
return buf.toString();
}
}
第二种方式在方法中AOP见
Asm实现静态AOP的两种方式-在进入方法和限出方法时注入代码实现aop代码增强