Java虚拟机--ASM(十八)
来源:互联网 发布:科幻小说推荐 知乎 编辑:程序博客网 时间:2024/05/22 12:56
- 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行,织入了对SecurityChecker。checkSecurity()的调用。如果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,将时间统计的字节码进行织入,运行以下代码:
输出结果如下:
- Java虚拟机--ASM(十八)
- 虚拟机下装oracle10G ASM
- ASM 翻译系列第三十八弹:ASM数据清理
- java ASM
- Java ASM
- java ASM
- java ASM
- ###ASM 翻译系列第二十八弹:ASM INTERNAL Partnership and Status Table
- linux基础(十八)管理虚拟机
- Core Java (十八) 断言
- JAVA学习总结十八
- ORACLE RAC 用虚拟机增加asm硬盘
- ASM---JAVA代码生成
- java ASM 指南 分析
- java asm 修改方法
- java asm 添加属性
- JAVA ASM AOP
- JAVA AOP之ASM
- Javascript let解析
- Android中的IPC之使用Bundle
- 数组的全排列
- 使用OC加载图片的两种方式及其区别
- Redis的安装和部署
- Java虚拟机--ASM(十八)
- ROC与AUC的定义与使用详解
- windows网络编程(一)
- uboot 启动延时,向kernel传递参数的设置
- 轻量级的.NET对象查找服务和AOP开发框架Netop.Core源码解说(5)--其它
- AbstractCollection 源码分析
- DOM编程
- 源码框架
- JVM 知识点总览