ASM simula AOP
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.
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();
}
}