ASM模拟AOP(计算方法执行时间)

ASM模拟AOP


ASM是一个通用的Java字节码操作和分析框架。它可以直接以二进制形式用于修改现有类或动态生成类。ASM提供了一些常见的字节码转换和分析算法,可以从中构建定制的复杂转换和代码分析工具。
ASM模拟AOP(计算方法执行时间)

maven依赖

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

目标实现逻辑

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");
    }
}

想在方法之前和之后打印时间,最终计算耗时。此时在IDEA中可以利用ASM插件获取ASMified文件。通过和原始的ASMified对比,然后抽取我们想要增强的ClassFile的指令集。

实现ClassVisitor和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);
        }
    }
}

增强输出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!!!");
    }
}

测试

public class MainTest {

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

ASM模拟AOP(计算方法执行时间)

上一篇:2021-03-25


下一篇:mv移动文件后内存未释放