Asm实现静态AOP的两种方式-生成java-proxy类

   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)。

Java proxy生成的代码(1):

 



接下来,我们来讲一下具体实现

首先第一步,需要写一个启动类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代码增强


评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值