ASM simula AOP (tiempo de ejecución del método de cálculo)


ASM es un marco general de análisis y manipulación de códigos de bytes de Java. Se puede usar directamente en forma binaria para modificar clases existentes o generar clases dinámicamente. ASM proporciona algunos algoritmos de análisis y conversión de código de bytes comunes a partir de los cuales se pueden construir herramientas de análisis de código y conversión complejas personalizadas.
Inserte la descripción de la imagen aquí

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

Lógica de realización de objetivos

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

Si desea imprimir el tiempo antes y después del método, el cálculo final requiere mucho tiempo. En este momento, puede utilizar el complemento ASM para obtener el archivo ASMified en IDEA. Comparándolo con el ASMified original, luego extraiga el conjunto de instrucciones del ClassFile que queremos mejorar.

Implementar ClassVisitor y 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);
        }
    }
}

Clase de salida mejorada

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

prueba

public class MainTest {
    
    

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

Inserte la descripción de la imagen aquí

Supongo que te gusta

Origin blog.csdn.net/GoSaint/article/details/115380959
Recomendado
Clasificación