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