-
Attribute类:字节码中属性的类抽象。
-
ByteVector类:字节码二进制存储的容器。
-
Opcodes接口:字节码指令的一些常量定义。
-
Type类:类型相关的常量定义以及一些基于其上的操作。
ClassReader是ASM中最核心的实现,它用于读取并解析Class字节码
在构建ClassReader实例时,它首先保存字节码二进制数组b,然后创建items数组,数组的长度在字节码数组的第8、9个字节指定(最前面4个字节是魔数CAFEBABE,之后2个字节是次版本号,再后2个字节是主版本号),每个item表示常量池项在字节码数组的偏移量加1(常量池中每个项由1个字节的type和紧跟的字节数组表示,常量池项有12种类型,其中CONSTANT_FieldRef_Info、CONSTANT_MethodRef_Info、CONSTANT_InterfaceMethodRef_Info、CONSTANT_NameAndType_Info包括其类型字节占用5个字节,另外4个字节每2个字节为字段、方法等所在的类、其名称、描述符在当前常量池中CONSTANT_Utf8_Info类型的引用;CONSTANT_Integer_Info、CONSTANT_Float_Info包括其类型字节占用5个字节,另外四个字节为其对应的值;CONSTANT_Class_Info、CONSTANT_String_Info包括其类型字节占用3个字节,另外两个字节为在当前常量池CONSTANT_Utf8_Info项的索引;CONSTANT_Utf8_Info类型第1个字节表示类型,第2、3个字节为该项所表示的字符串的长度);CONSTANT_Double_Info、CONSTANT_Long_Info加类型字节为9个字;maxStringLength表示最长的UTF8类型的常量池项的值,用于决定在解析CONSTANT_Utf8_Info类型项时最大需要的字符数组;header表示常量池之后的字节码的第一个字节。
=====================================================================
IDEA使用插件 asm outline 查看 asm 如何生成该类。
- 类实现
对应的 asm 编程代码
package asm.com.javaedge.asm;
import java.util.*;
import org.objectweb.asm.*;
public class TestAsmDump implements Opcodes {
public static byte[] dump() throws Exception {
ClassWriter cw = new ClassWriter(0);
FieldVisitor fv;
MethodVisitor mv;
AnnotationVisitor av0;
cw.visit(52, ACC_PUBLIC + ACC_SUPER, “com/javaedge/asm/TestAsm”, null, “java/lang/Object”, null);
cw.visitSource(“TestAsm.java”, null);
{
mv = cw.visitMethod(ACC_PUBLIC, “”, “()V”, null, null);
mv.visitCode();
Label l0 = new Label();
mv.visitLabel(l0);
mv.visitLineNumber(7, l0);
mv.visitVarInsn(ALOAD, 0);
mv.visitMethodInsn(INVOKESPECIAL, “java/lang/Object”, “”, “()V”, false);
mv.visitInsn(RETURN);
Label l1 = new Label();
mv.visitLabel(l1);
mv.visitLocalVariable(“this”, “Lcom/javaedge/asm/TestAsm;”, null, l0, l1, 0);
mv.visitMaxs(1, 1);
mv.visitEnd();
}
{
mv = cw.visitMethod(ACC_PUBLIC, “m”, “()V”, null, null);
mv.visitCode();
Label l0 = new Label();
Label l1 = new Label();
Label l2 = new Label();
mv.visitTryCatchBlock(l0, l1, l2, “java/lang/InterruptedException”);
Label l3 = new Label();
mv.visitLabel(l3);
mv.visitLineNumber(10, l3);
mv.visitFieldInsn(GETSTATIC, “java/lang/System”, “out”, “Ljava/io/PrintStream;”);
mv.visitLdcInsn(“Hello ASM”);
mv.visitMethodInsn(INVOKEVIRTUAL, “java/io/PrintStream”, “println”, “(Ljava/lang/String;)V”, false);
mv.visitLabel(l0);
mv.visitLineNumber(12, l0);
mv.visitLdcInsn(new Long(100L));
mv.visitMethodInsn(INVOKESTATIC, “java/lang/Thread”, “sleep”, “(J)V”, false);
mv.visitLabel(l1);
mv.visitLineNumber(15, l1);
Label l4 = new Label();
mv.visitJumpInsn(GOTO, l4);
mv.visitLabel(l2);
mv.visitLineNumber(13, l2);
mv.visitFrame(Opcodes.F_SAME1, 0, null, 1, new Object[]{“java/lang/InterruptedException”});
mv.visitVarInsn(ASTORE, 1);
Label l5 = new Label();
mv.visitLabel(l5);
mv.visitLineNumber(14, l5);
mv.visitVarInsn(ALOAD, 1);
mv.visitMethodInsn(INVOKEVIRTUAL, “java/lang/InterruptedException”, “printStackTrace”, “()V”, false);
mv.visitLabel(l4);
mv.visitLineNumber(16, l4);
mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null);
mv.visitInsn(RETURN);
Label l6 = new Label();
mv.visitLabel(l6);
mv.visitLocalVariable(“e”, “Ljava/lang/InterruptedException;”, null, l5, l4, 1);
mv.visitLocalVariable(“this”, “Lcom/javaedge/asm/TestAsm;”, null, l3, l6, 0);
mv.visitMaxs(2, 2);
mv.visitEnd();
}
cw.visitEnd();
return cw.toByteArray();
}
}
看看最简单的统计方法执行时间
…
mv.visitMethodInsn(INVOKESTATIC, “java/lang/System”, “currentTimeMillis”, “()J”, false);
mv.visitVarInsn(LSTORE, 1);
…
mv.visitFieldInsn(GETSTATIC, “java/lang/System”, “out”, “Ljava/io/PrintStream;”);
mv.visitLdcInsn(“Hello ASM”);
mv.visitMethodInsn(INVOKEVIRTUAL, “java/io/PrintStream”, “println”, “(Ljava/lang/String;)V”, false);
mv.visitLabel(l0);
mv.visitLineNumber(13, l0);
mv.visitLdcInsn(new Long(100L));
mv.visitMethodInsn(INVOKESTATIC, “java/lang/Thread”, “sleep”, “(J)V”, false);
mv.visitLabel(l1);
mv.visitLineNumber(16, l1);
Label l5 = new Label();
mv.visitJumpInsn(GOTO, l5);
mv.visitLabel(l2);
mv.visitLineNumber(14, l2);
mv.visitFrame(Opcodes.F_FULL, 2, new Object[]{“com/javaedge/asm/TestAsm”, Opcodes.LONG}, 1, new Object[]{“java/lang/InterruptedException”});
mv.visitVarInsn(ASTORE, 3);
Label l6 = new Label();
mv.visitLabel(l6);
mv.visitLineNumber(15, l6);
mv.visitVarInsn(ALOAD, 3);
mv.visitMethodInsn(INVOKEVIRTUAL, “java/lang/InterruptedException”, “printStackTrace”, “()V”, false);
mv.visitLabel(l5);
mv.visitLineNumber(17, l5);
mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null);
mv.visitMethodInsn(INVOKESTATIC, “java/lang/System”, “currentTimeMillis”, “()J”, false);
mv.visitVarInsn(LSTORE, 3);
Label l7 = new Label();
mv.visitLabel(l7);
mv.visitLineNumber(18, l7);
mv.visitFieldInsn(GETSTATIC, “java/lang/System”, “out”, “Ljava/io/PrintStream;”);
mv.visitTypeInsn(NEW, “java/lang/StringBuilder”);
mv.visitInsn(DUP);
mv.visitMethodInsn(INVOKESPECIAL, “java/lang/StringBuilder”, “”, “()V”, false);
mv.visitLdcInsn("m\u65b9\u6cd5\u6267\u884c\u65f6\u95f4: ");
mv.visitMethodInsn(INVOKEVIRTUAL, “java/lang/StringBuilder”, “append”, “(Ljava/lang/String;)Ljava/lang/StringBuilder;”, false);
mv.visitVarInsn(LLOAD, 3);
mv.visitVarInsn(LLOAD, 1);
mv.visitInsn(LSUB);
mv.visitMethodInsn(INVOKEVIRTUAL, “java/lang/StringBuilder”, “append”, “(J)Ljava/lang/StringBuilder;”, false);
mv.visitMethodInsn(INVOKEVIRTUAL, “java/lang/StringBuilder”, “toString”, “()Ljava/lang/String;”, false);
mv.visitMethodInsn(INVOKEVIRTUAL, “java/io/PrintStream”, “println”, “(Ljava/lang/String;)V”, false);
Label l8 = new Label();
mv.visitLabel(l8);
mv.visitLineNumber(19, l8);
mv.visitInsn(RETURN);
Label l9 = new Label();
mv.visitLabel(l9);
mv.visitLocalVariable(“e”, “Ljava/lang/InterruptedException;”, null, l6, l5, 3);
最后
我还为大家准备了一套体系化的架构师学习资料包以及BAT面试资料,供大家参考及学习
已经将知识体系整理好(源码,笔记,PPT,学习视频)
new Label();
mv.visitLabel(l9);
mv.visitLocalVariable(“e”, “Ljava/lang/InterruptedException;”, null, l6, l5, 3);
最后
我还为大家准备了一套体系化的架构师学习资料包以及BAT面试资料,供大家参考及学习
已经将知识体系整理好(源码,笔记,PPT,学习视频)
[外链图片转存中…(img-VFU6y3R5-1721131262138)]
[外链图片转存中…(img-WKiYFVqG-1721131262138)]
[外链图片转存中…(img-4YNvQIjk-1721131262139)]