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

来源:互联网 发布:狗粮 饼干 淘宝 编辑:程序博客网 时间:2024/05/16 12:07

   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()throwsException {
                    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=newHashSet<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=newArrayList<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代码增强


0 0
原创粉丝点击