Java字节码框架ASM简介

  • 1. ASM概述
    • 1.1 ASM简介
    • 1.2 ASM提供API
    • 1.3 ASM核心模块
  • 2. ASM应用
    • 2.1 ASM依赖
    • 2.2 代码实现
    • 2.3 测试验证

1. ASM概述

1.1 ASM简介

ASM 是一个通用的 Java 字节码操作和分析框架。一般用来动态生成类或者增强既有类的功能。也就是既可以创建class文件,也可以修改class文件。

ASM官网地址:https://asm.ow2.io/index.html

1.2 ASM提供API

ASM提供了两种API
Core API(ClassVisitor 、MethodVisitor等)
Tree API(ClassNode,MethodNode等)
ASM API文档地址:https://asm.ow2.io/asm4-guide.pdf

1.3 ASM核心模块

ClassReader 负责解析 .class 文件中的字节码,并将所有字节码传递给 ClassWriter。

ClassVisitor: 负责访问.class文件的各个元素,可以解析或者修改.class文件的内容。

ClassWriter:继承自 ClassVisitor,它是生成字节码的工具类,负责将修改后的字节码输出为 byte 数组。

2. ASM应用

2.1 ASM依赖

mvn仓库地址:https://mvnrepository.com/artifact/org.ow2.asm/asm/9.2

<!-- https://mvnrepository.com/artifact/org.ow2.asm/asm -->
<dependency><groupId>org.ow2.asm</groupId><artifactId>asm</artifactId><version>9.2</version>
</dependency>

2.2 代码实现

Employee

/*** @author zrj* @since 2022/1/24**/
public class Employee {private String employeeName;public void working() {System.out.println(employeeName + " is working !");}
}

EmployeeClassLoader

/*** @author zrj* @since 2022/1/24**/
public class EmployeeClassLoader extends ClassLoader {public Class defineClassFromClassFile(String className,byte[] classFile) throws ClassFormatError{return defineClass(className, classFile, 0, classFile.length);}public Class<?> defineClassForName(String name, byte[] data) {return this.defineClass(name, data, 0, data.length);}
}

EmployeeClassVisitor

import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.FieldVisitor;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;/*** @author zrj* @since 2022/1/24**/
public class EmployeeClassVisitor extends ClassVisitor {private String className;private String superName;public EmployeeClassVisitor(ClassVisitor classVisitor) {super(Opcodes.ASM5, classVisitor);}@Overridepublic void visit(int version, int access, String name, String signature, String superName, String[] interfaces) {this.className = name;this.superName = superName;//super.visit(version, access, name, signature, superName, interfaces);super.visit(version, access, name + "$EnhancedByASM", signature, name, interfaces);}@Overridepublic FieldVisitor visitField(int access, String name, String desc, String signature, Object value) {System.out.println("【ClassVisitor visitField 】access:" + access + ", name:" + name + ", desc:" + desc + ",signature:" + signature + ",value:" + value);return super.visitField(access, name, desc, signature, value);}@Overridepublic MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) {System.out.println("【ClassVisitor visitMethod】access:" + access + ", name:" + name + ", desc:" + desc + ", signature:" + signature + ", exceptions:" + exceptions);MethodVisitor mv = super.visitMethod(access, name, desc, signature, exceptions);MethodVisitor wrappedMv = mv;//判断当前读取的方法if ("working".equals(name)) {//如果是working方法,则包装一个方法的VisitorwrappedMv = new EmployeeMethodVisitor(Opcodes.ASM5, mv);} else if ("<init>".equals(name)) {//如果是构造方法,处理子类中父类的构造函数调用wrappedMv = new EmployeeConstructorMethodVisitor(Opcodes.ASM5, mv, superName);}return wrappedMv;}
}

EmployeeMethodVisitor.java

import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;/*** @author zrj* @since 2022/1/24**/
public class EmployeeMethodVisitor extends MethodVisitor {private String className;private String methodName;public EmployeeMethodVisitor(int Opcodes, MethodVisitor methodVisitor) {super(Opcodes, methodVisitor);}//MethodVisitor 中定义了不同的visitXXX()方法,代表的不同的访问阶段。//visitCode表示刚刚进入方法。@Overridepublic void visitCode() {//添加一行System.currentTimeMillis()调用visitMethodInsn(Opcodes.INVOKESTATIC, "java/lang/System", "currentTimeMillis", "()J", false);//并且将其存储在局部变量表内位置为1的地方visitVarInsn(Opcodes.LSTORE, 1);//上面两个的作用就是在Studying方法的第一行添加 long start = System.currentTimeMillis()}//visitInsn 表示访问进入了方法内部@Overridepublic void visitInsn(int opcode) {//通过opcode可以得知当前访问到了哪一步,如果是>=Opcodes.IRETURN && opcode <= Opcodes.RETURN 表明方法即将退出if ((opcode >= Opcodes.IRETURN && opcode <= Opcodes.RETURN)) {//加载局部变量表中位置为1的数据,也就是start的数据,并传入给下面的方法visitVarInsn(Opcodes.LLOAD, 1);//然后调用自定义的一个工具方法,用来输出耗时visitMethodInsn(Opcodes.INVOKESTATIC, "com/zjz/Before", "end", "(J)V", false);}super.visitInsn(opcode);}}class EmployeeConstructorMethodVisitor extends MethodVisitor {//定义一个全局变量记录父类名称private String superClassName;public EmployeeConstructorMethodVisitor(int i, MethodVisitor methodVisitor, String superClassName) {super(i, methodVisitor);this.superClassName = superClassName;}@Overridepublic void visitMethodInsn(int opcode, String owner, String name, String desc, boolean b) {//当开始初始化构造函数时,先访问父类构造函数,类似源码中的super()if (opcode == Opcodes.INVOKESPECIAL && name.equals("<init>")) {owner = superClassName;}super.visitMethodInsn(opcode, owner, name, desc, b);}
}

EmployeeOw2AsmTest

import org.objectweb.asm.*;import java.io.FileOutputStream;/*** @author zrj* @since 2022/1/24**/
public class EmployeeOw2AsmTest {public static void main(String[] args) throws Exception {//1.定义ClassReaderString sourceClassName = "com.zrj.unit.asm.Employee";ClassReader classReader = new ClassReader(sourceClassName);//2.定义ClassWriterClassWriter classWriter = new ClassWriter(classReader, ClassWriter.COMPUTE_MAXS);//3.定义ClassVisitorClassVisitor classVisitor = new EmployeeClassVisitor(classWriter);// 定义classVisitor输入数据,// SKIP_DEBUG 如果设置了此标志,则这些属性既不会被解析也不会被访问// EXPAND_FRAMES 依次调用ClassVisitor 接口的各个方法classReader.accept(classVisitor, ClassReader.EXPAND_FRAMES);// 将最终修改的字节码以byte数组形式返回byte[] bytes = classWriter.toByteArray();String targetClassName = "com.zrj.unit.asm.Employee$EnhancedByASM";Class<?> clazz = new EmployeeClassLoader().defineClassFromClassFile(targetClassName, bytes);System.out.println("【EmployeeOw2AsmTest】clazz:" + clazz);// 通过文件流写入方式覆盖原先的内容,实现class文件的改写FileOutputStream fileOutputStream = new FileOutputStream("D:\\data\\asm\\Employee$EnhancedByASM.class");fileOutputStream.write(bytes);fileOutputStream.close();}}

2.3 测试验证

【ClassVisitor visitField 】access:2, name:employeeName, desc:Ljava/lang/String;,signature:null,value:null
【ClassVisitor visitMethod】access:1, name:<init>, desc:()V, signature:null, exceptions:null
【ClassVisitor visitMethod】access:9, name:main, desc:([Ljava/lang/String;)V, signature:null, exceptions:null
【EmployeeOw2AsmTest】clazz:class com.zrj.unit.asm.Employee$EnhancedByASM

Java字节码框架ASM简介相关推荐

  1. CGLIB依赖ASM(关于java字节码框架ASM的学习)

    本文转自: http://www.cnblogs.com/liuling/archive/2013/05/25/asm.html 一.什么是ASM ASM是一个java字节码操纵框架,它能被用来动态生 ...

  2. koala java,GitHub - lijiankun24/Koala: 从 Java 字节码到 ASM 实践

    Koala 相关博文 在开发之前学习了一些 Java 字节码.Java 虚拟机.ASM 的相关知识,梳理成博文如下,请多多指教 简介 在开发项目的时候,经常会想看一个方法的入参.返回结果和执行耗时,我 ...

  3. 【字节码】字节码操作 ASM 简介

    1. ASM是什么? 简单来说, ASM是-个操他ava字节砂的类库. 为了能够更好的理解ASM是什么, 我们需要来搞清楚两个问题: 第一个问题,ASM的操作对象是什么呢? 第二个问题,ASM是如何处 ...

  4. asm(Java字节码操控框架)和 CGlib(Code Generation Library)

    asm概述 asm 是一个 Java 字节码操控框架. 它能够以二进制形式修改已有类或者动态生成类.ASM 可以直接产生二进制 class 文件,也可以在类被加载入Java 虚拟机之前动态改变类行为. ...

  5. java 字节码增强之ASM

    ASM系列之一:初探ASM 一.什么是ASM ASM是一个JAVA字节码分析.创建和修改的开源应用框架.在ASM中提供了诸多的API用于对类的内容进行字节码操作的方法.与传统的BCEL和SERL不同, ...

  6. Java字节码技术(二)字节码增强之ASM、JavaAssist、Agent、Instrumentation

    文章目录 前言 从AOP说起 静态代理 动态代理 JavaProxy CGLIB 字节码增强实现AOP ASM JavaAssist 运行时类加载 Instrumentation接口 JavaAgen ...

  7. asm java字节码操控工具学习

    #ASM技术研究 ##ASM是什么 ASM 是一个 Java 字节码操控框架.它能被用来动态生成类或者增强既有类的功能.ASM 可以直接产生二进制 class 文件,也可以在类被加载入 Java 虚拟 ...

  8. 小师妹学JVM之:java的字节码byte code简介

    文章目录 简介 Byte Code的作用 查看Byte Code字节码 java Byte Code是怎么工作的 总结 简介 Byte Code也叫做字节码,是连接java源代码和JVM的桥梁,源代码 ...

  9. 定义入栈java_小师妹学JVM之:java的字节码byte code简介

    简介 Byte Code也叫做字节码,是连接java源代码和JVM的桥梁,源代码编译成为字节码,而字节码又被加载进JVM中运行.字节码怎么生成,怎么查看字节码,隐藏在Byte Code背后的秘密是什么 ...

最新文章

  1. css选择器 nth-child
  2. dojo中 xhr.post向后台传参出现乱码
  3. 硬货 - 技术人也能轻松玩转公众号?正确姿势竟然是...
  4. vertex shader(5)
  5. 使用CRT调试功能来检测内存泄漏
  6. ros openwrt 分流_常平:推进“截污大会战”补贴助力企业雨污分流
  7. vue 父链和子组件索引_解决Vue2.x父组件与子组件之间的双向绑定问题
  8. Tuple and Tie
  9. pytorch自我错误总结
  10. 史上讲解最好的 Docker 教程
  11. openstack手动部署简单记录
  12. docker工作原理、组成部分、特点优点
  13. Vmix噪音抑制插件的使用,大大改善音频监听效果
  14. Microstation v8+Terrasolid安装教程
  15. .js ruby如何调用_为什么我们喜欢并选择Ruby而不是Node.js?
  16. PHP自动全局变量漏洞 rips工具使用
  17. faxicon.ico制作(笔记)
  18. 企业简介和公司介绍快闪PPT模板
  19. Springboot毕设项目理财管理系统mnl7cjava+VUE+Mybatis+Maven+Mysql+sprnig)
  20. 阿里云ECS服务器使用要求及不可以进行的操作

热门文章

  1. Python 的类(菜鸟教程)
  2. 华为odjava机试题_华为OD机试 :找终点
  3. (七)JMockit 的MockUp+@Mock--基础篇
  4. 金仓数据库 KingbaseGIS 使用手册(8.11. 栅格处理函数)
  5. Cheat Engine 小白教程(大白话教学 下篇
  6. EXTJS 6 Grid 滚动到底部 触发事件(如:加载数据)
  7. 宏名字不规范,与结构体的成员重名
  8. 24个提高你的知识和技能极限的数据科学(机器学习)项目(免费)
  9. pyqt5QQ音乐播放器毕设成品音频可视化
  10. 代理对推广网站的四个作用