ASM simulates AOP (calculation method execution time)


ASM is a general Java bytecode manipulation and analysis framework. It can be used directly in binary form to modify existing classes or dynamically generate classes. ASM provides some common bytecode conversion and analysis algorithms from which customized complex conversion and code analysis tools can be constructed.
Insert picture description here

maven dependency

       <dependency>
            <groupId>org.ow2.asm</groupId>
            <artifactId>asm</artifactId>
            <version>9.1</version>
        </dependency>

        <dependency>
            <groupId>org.ow2.asm</groupId>
            <artifactId>asm-util</artifactId>
            <version>9.1</version>
        </dependency>

Goal realization logic

public class App {
    
    

    public void method()  {
    
    
        long start=System.currentTimeMillis();
        System.out.println("invoke method start......");
        try {
    
    
            Thread.sleep(100);
        } catch (InterruptedException e) {
    
    
            e.printStackTrace();
        }
        long end=System.currentTimeMillis();
        System.out.println("method user time == "+(end-start)+"ms");
    }
}

Want to print the time before and after the method, the final calculation is time-consuming. At this point, you can use the ASM plug-in to obtain the ASMified file in IDEA. By comparing with the original ASMified, then extract the instruction set of the ClassFile we want to enhance.

Implement ClassVisitor and MethodVisitor

public class MyVisitor extends ClassVisitor {
    
    

    public MyVisitor(ClassVisitor classVisitor) {
    
    
        super(Opcodes.ASM9, classVisitor);
    }

    @Override
    public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) {
    
    
        cv.visit(version, access, name, signature, superName, interfaces);
    }

    @Override
    public MethodVisitor visitMethod(int access, String name, String descriptor, String signature, String[] exceptions) {
    
    
        //这里开始对方法进行增强
        MethodVisitor mv = cv.visitMethod(access, name, descriptor, signature, exceptions);
        if (!"<init>".equals(name) && mv != null) {
    
    
            //对于特定的方法增强
            mv=new MyMethodVisitor(mv);
        }
        return mv;
    }

    /**
     * 方法访问类
     */
    class MyMethodVisitor extends MethodVisitor {
    
    


        public MyMethodVisitor(MethodVisitor methodVisitor) {
    
    
            super(Opcodes.ASM9, methodVisitor);
        }

        @Override
        public void visitCode() {
    
    
            mv.visitCode();
            mv.visitMethodInsn(Opcodes.INVOKESTATIC, "java/lang/System", "currentTimeMillis", "()J", false);
            mv.visitVarInsn(Opcodes.LSTORE, 1);
        }

        @Override
        public void visitInsn(int opcode) {
    
    
            if ((opcode >= Opcodes.IRETURN && opcode <= Opcodes.RETURN) ||
                    opcode == Opcodes.ATHROW) {
    
    
                mv.visitMethodInsn(Opcodes.INVOKESTATIC, "java/lang/System", "currentTimeMillis", "()J", false);
                mv.visitVarInsn(Opcodes.LSTORE, 3);
                Label label7 = new Label();
                mv.visitLabel(label7);
                mv.visitLineNumber(14, label7);
                mv.visitFieldInsn(Opcodes.GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;");
                mv.visitVarInsn(Opcodes.LLOAD, 3);
                mv.visitVarInsn(Opcodes.LLOAD, 1);
                mv.visitInsn(Opcodes.LSUB);
                mv.visitInvokeDynamicInsn("makeConcatWithConstants", "(J)Ljava/lang/String;", new Handle(Opcodes.H_INVOKESTATIC, "java/lang/invoke/StringConcatFactory", "makeConcatWithConstants", "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/invoke/CallSite;", false), new Object[]{
    
    "method user time == \u0001ms"});
                mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/io/PrintStream", "println", "(Ljava/lang/String;)V", false);
            }
            mv.visitInsn(opcode);
        }
    }
}

Enhanced output class

public class Generator {
    
    

    public static void main(String[] args) throws IOException {
    
    
        ClassReader cr = new ClassReader("com/gosaint/asm/App");
        ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS);
        ClassVisitor cv = new MyVisitor(cw);
        //跳过调试
        cr.accept(cv, ClassReader.SKIP_DEBUG);
        byte[] data = cw.toByteArray();
        File f = new File("target/classes/com/gosaint/asm/App.class");
        FileOutputStream fos = new FileOutputStream(f);
        fos.write(data);
        fos.close();
        System.out.println("Generator App class success!!!");
    }
}

test

public class MainTest {
    
    

    public static void main(String[] args) throws InterruptedException {
    
    
        App a=new App();
        a.method();
    }
}

Insert picture description here

Guess you like

Origin blog.csdn.net/GoSaint/article/details/115380959