深刻字节码 -- 玩转 ASM-Bytecode

    本文是《深刻字节码 -- 使用 ASM 实现 AOP》的后续博文。在上一篇文章中介绍了如何使用 ASM 动态安插代码到类中,从而简单实现 Aop。文章获得了广大朋友好评,我也但愿能够不负众望继续写出能够获得你们承认的更多相关文章。废话很少进入正题。 java

    古语有云“工欲善其事,必先利其器”。因为 JVM 对字节码十分敏感修改过程当中稍微有一丝错误都会致使虚拟机错误,而想要排查错误倒是一件比较困难的事情。再加上后面的博文将会很大程度上依赖 “ASM-Bytecode” 工具。所以我以为有必要在深刻制定字节码以前介绍一下如何使用 “ASM-Bytecode” 。 eclipse

    首先安装Eclipse插件,插件的地址为:“http://andrei.gmxhome.de/eclipse/” 个人 Eclipse 版本为 3.7。
编辑器

安装完成以后重启 Eclipse ,打开菜单 Window -> Show View -> Other... 在分类中选择 Bytecode 视图
工具

    为了测试其功能随便建立一个工程并新建一个 HalloWord 程序,在 Eclipse 中打开 “HalloWord.java” 程序查看 Bytecode 视图,你会获得下面这样的代码。
    (注意:因为Bytecode会自动感知 Eclipse 编辑器中光标位置从而肯定生成的代码范围所以初学者建议将光标放到 “main” 方法中) 测试

// access flags 0x9
  public static main(String[]) : void
   L0
    LINENUMBER 22 L0
    GETSTATIC System.out : PrintStream
    LDC "Hallo Word"
    INVOKEVIRTUAL PrintStream.println(String) : void
   L1
    LINENUMBER 23 L1
    RETURN
   L2
    LOCALVARIABLE args String[] L0 L2 0
    MAXSTACK = 2
    MAXLOCALS = 1
    这是 ASM 为咱们生成的 “main” 方法字节码指令。点击 “Bytecode”  视图右上角红色的 “ASM” 按钮。ASM便会为咱们生成想要的 ASM 代码。
{
mv = cw.visitMethod(ACC_PUBLIC + ACC_STATIC, "main", "([Ljava/lang/String;)V", null, null);
mv.visitCode();
Label l0 = new Label();
mv.visitLabel(l0);
mv.visitLineNumber(22, l0);
mv.visitFieldInsn(GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;");
mv.visitLdcInsn("Hallo Word");
mv.visitMethodInsn(INVOKEVIRTUAL, "java/io/PrintStream", "println", "(Ljava/lang/String;)V");
Label l1 = new Label();
mv.visitLabel(l1);
mv.visitLineNumber(23, l1);
mv.visitInsn(RETURN);
Label l2 = new Label();
mv.visitLabel(l2);
mv.visitLocalVariable("args", "[Ljava/lang/String;", null, l0, l2, 0);
mv.visitMaxs(2, 1);
mv.visitEnd();
}
    “Bytecode ” 程序总会为咱们生成不少没必要要的代码,为此打开 Window -> Preferences 找到 Bytecode Outline 选项关闭 “Show line info”、 “Show variables” 两个选项。这两个选项分别是用来生成行号代码和本地变量表代码。这样作能够大大减小所要分析的内容,不过即使如此 “Bytecode Outline” 的生成代码中依然保留了不少没必要要的 “垃圾” 。

    最后获得以下精简的 ASM 生成内容:4,5,9,10,12,13 行代码仍然是垃圾。很惋惜 “ Bytecode Outline ” 只帮咱们去掉了 “visitLineNumber” 这样的代码,其余两行并未给予处理。只要记得这个是目前是用来表示行号便可。
{
mv = cw.visitMethod(ACC_PUBLIC + ACC_STATIC, "main", "([Ljava/lang/String;)V", null, null);
mv.visitCode();
Label l0 = new Label();
mv.visitLabel(l0);
mv.visitFieldInsn(GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;");
mv.visitLdcInsn("Hallo Word");
mv.visitMethodInsn(INVOKEVIRTUAL, "java/io/PrintStream", "println", "(Ljava/lang/String;)V");
Label l1 = new Label();
mv.visitLabel(l1);
mv.visitInsn(RETURN);
Label l2 = new Label();
mv.visitLabel(l2);
mv.visitMaxs(2, 1);
mv.visitEnd();
}

    要注意的是虽然借助 “Bytecode Outline” 咱们只须要提供一份代码模板便可生成各类 ASM 代码,可是,切莫生成过于复杂的代码 spa

    到这里使用 “Bytecode Outline” 生成 ASM 代码部分就介绍这么多,在下一篇文章中将重点介绍 ASM 核心接口方法。 .net

相关文章
相关标签/搜索