Java虚拟机--ASM(十八)

  • ASM体系结构
    • ASM是Java字节码的操作库,包括Eclipse,Spring,CGLIB都是ASM的使用者;
    • 优势:
      • 性能高;
      • 直接工作于底层,使用更加灵活与强大;
    • 劣势:
      • 相对复杂;
    • 核心组件
      • Opcodes接口定义了一些常量,尤其是版本号,访问标示符,字节码等信息;
      • ClassReader用于读取Class文件,主要用于Class文件的分析,可接受一个ClassVisitor;
        • ClassReader会将解析过程中产生的类的部分信息,比如访问标识符,字段,方法逐个送入ClassVisitor,后者在接收到对应的信息后,进行各自的处理;
      • ClassVisitor的子类ClassWriter,负责进行Class文件的输出和生成。ClassVisitor在进行字段和方法处理的时候,会委托给FieldVistor和MethodVisitor进行处理;
        • 在类的处理过程中,会创建对应的FieldVisitor和MethodVisitor对象;
        • FieldVisitor和MethodVisitor类也各自有1个重要的子类,FieldWriter和MethodWriter;当ClassWriter进行字段和方法的处理时,也是依赖这两个类进行的;
      • ClassVisitor,FieldVisitor,MethodVisitor都可以使用委托的方式,将实际的处理工作交给内部的委托类进行;它们内部有一些列的visitXXX方法:
        • 这些方法在ClassWriter和MethodWriter内部实现时,绝大部分情况下,都会去生成该方法对应的内容;
          • 比如,当MethodWriter的visitInsn(int opcode)方法被调用时,MethodWriter就会生成一条由参数opcode指定的字节码;
          • 而visitInsn(int opcode)方法作为MethodVisitor的方法,将会在ClassReader访问Class时被回调;
          • 即,当使用ClassReader读取一个类,ClassWriter作为访问者时,当ClassReader读取到一条不带参数的字节码信息时,就会通知ClassWriter,visitInsn(int opcode)方法,让ClassWriter生成这条字节码信息;
  • 示例:为类增加安全控制
    • 现在有一个账户类,可以进行某些操作如下:

现在要为operation()方法增加一些安全校验,以判断这个对象是否有权限执行这个方法,如果有,则执行该方法,如果没有,则直接退出。

增加的权限校验函数:

该代码模拟了权限校验,通过随机方式给出是否校验通过。现在系统要做的就是将SecurityChecker.checkSecurity()函数置于Account.operation()函数之前运行,如果权限校验失败,则阻止Account.operation()继续处理;

  • 下面的SecurityWeaveGenerator类,将checkSecutrity()函数放置到operation()函数的第1行执行。它的核心是代码第6行的AddSecurityCheckClassAdapter类。这是一个ClassVisitor,它负责实际的字节码织入操作。在代码的第8~12行,将新生成的Account类写入文件,覆盖由Java编译器产生的Account类的Class文件;

AddSecurityCheckClassAdapter类的代码如下:

在AddSecurityCheckClassAdapter中,覆盖了visitMethod()方法,在代码第11行,当访问到operation方法时,交由AddSecutiryCheckMethodAdapter类处理。AddSecutiryCheckMethodAdapter是一个MethodVisitor,它负责最终的字节码修改:

AddSecurityCheckClassAdapter类覆盖了MethodVisitor的visitCode()方法。当访问到方法的字节码时,在第7~12行,织入了对SecurityCheckercheckSecurity()的调用。如果checkSecurity()返回了false(栈顶为0),根据指令ifne,跳转不会发生,程序返回。如果checkSecurity()返回了true(栈顶为1),则指令ifne发生跳转,继续执行原先的operation()操作

先使用javac编译并生成Account.class,接着使用SecurityWeaveGenerator类对Account.class进行处理,织入权限校验的字节码,最后使用下面的代码测试:

  • 统计函数执行时间示例
    • 统计函数时间可利用System.currentTImeMillis(),现在可利用ASM框架,在不修改源码,不改变原有系统的情况下,直接将统计函数织入系统;
    • 利用Thread.sleep()模拟一段耗时的函数调用,现在Account.operation()本身并不具有计时功能

    • 现在,加入计时统计功能:

TimeStat实现了函数的调用计时,在进入函数时,可以使用start()方法表示函数调用开始,在离开函数时,使用end()方法表示函数调用结束。函数调用结束后,打印出当前正在调用的函数名称以及实际的系统耗时。

  • 现在将统计时间代码织入Account.operation()

6行使用TimeStatClassAdapter类,完成具体的字节码修改工作。修改完成后,第9~12行写入Class文件,覆盖原有的Class文件。
 

  • TimeStatClassAdapter是一个ClassVisitor,这里,需要覆盖它的visitMethod()方法,对operation()方法进行修改;

此段代码在访问方法时,判断是否是operation()方法,如果是,则进行方法字节码的调整,并将这个这个工作委托给TimeStatMethodAdapter完成。

  • TimeStatMethodAdapter的实现

6行的visitCode()在方法Code属性被访问时调用,因此,这里插入对TimeStat.start()方法的调用,表示方法的开始。
12行,覆盖了visitInsn()函数,当访问到xreturn指令时,进行TimeStat.end()函数调用,表示方法即将退出。

  • 从字节码上的指令看多个xreturn指令是连续的,如下所示:

  • 因此在visitInsn()中,简单地通过指令值获得范围,判断是否为xreturn函数返回指令。使用TimeStatWeaveGenerator修改Account.class,将时间统计的字节码进行织入,运行以下代码:

输出结果如下:

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
使用 ASM 库可以轻松地读取和编辑 Java 类文件。下面是一个简单的示例,演示如何使用 ASM 读取类文件并输出类中的所有方法名称: ```java import org.objectweb.asm.ClassReader; import org.objectweb.asm.ClassVisitor; import org.objectweb.asm.MethodVisitor; import org.objectweb.asm.Opcodes; import java.io.IOException; public class ReadClass { public static void main(String[] args) throws IOException { String className = "com/example/MyClass"; ClassReader classReader = new ClassReader(className); classReader.accept(new ClassPrinter(), 0); } static class ClassPrinter extends ClassVisitor { public ClassPrinter() { super(Opcodes.ASM5); } @Override public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) { System.out.println("Method: " + name); return null; } } } ``` 在此示例中,我们使用 `ClassReader` 类读取名为 `com.example.MyClass` 的类文件,然后将其传递给 `ClassPrinter` 类的实例进行处理。`ClassPrinter` 类扩展自 `ClassVisitor` 类,可以在处理类文件时拦截各种事件。在此示例中,我们只重写了 `visitMethod` 方法,并在其中输出方法名称。当 `ClassReader` 读取到类文件中的每个方法时,会调用 `visitMethod` 方法并将方法信息传递给它。 你也可以使用 ASM 编辑器来修改类文件。例如,可以使用 `ClassWriter` 创建新的类文件,并使用 `MethodVisitor` 添加新的方法。具体实现可以参考 ASM 官方文档。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值