一、什么是ASM

ASM是一个java字节码操纵框架,它能被用来动态生成类或者增强既有类的功能。ASM 可以直接产生二进制 class 文件,也可以在类被加载入 Java 虚拟机之前动态改变类行为。Java class 被存储在严格格式定义的 .class文件里,这些类文件拥有足够的元数据来解析类中的所有元素:类名称、方法、属性以及 Java 字节码(指令)。ASM从类文件中读入信息后,能够改变类行为,分析类信息,甚至能够根据用户要求生成新类。

使用ASM框架需要导入asm的jar包,下载链接:asm-3.2.jar。

二、如何使用ASM

ASM框架中的核心类有以下几个:

① ClassReader:该类用来解析编译过的class字节码文件。

② ClassWriter:该类用来重新构建编译后的类,比如说修改类名、属性以及方法,甚至可以生成新的类的字节码文件。

③ ClassAdapter:该类也实现了ClassVisitor接口,它将对它的方法调用委托给另一个ClassVisitor对象。

示例1.通过asm生成类的字节码java 字节码框架 asmpackage com.asm3;

import java.io.File;

import java.io.FileNotFoundException;

import java.io.FileOutputStream;

import java.io.IOException;

import org.objectweb.asm.ClassWriter;

import org.objectweb.asm.Opcodes;

/**

* 通过asm生成类的字节码

* @author Administrator

*

*/

public class GeneratorClass {

public static void main(String[] args) throws IOException {

//生成一个类只需要ClassWriter组件即可

ClassWriter cw = new ClassWriter(0);

//通过visit方法确定类的头部信息

cw.visit(Opcodes.V1_5, Opcodes.ACC_PUBLIC+Opcodes.ACC_ABSTRACT+Opcodes.ACC_INTERFACE,

"com/asm3/Comparable", null, "java/lang/Object", new String[]{"com/asm3/Mesurable"});

//定义类的属性

cw.visitField(Opcodes.ACC_PUBLIC+Opcodes.ACC_FINAL+Opcodes.ACC_STATIC,

"LESS", "I", null, new Integer(-1)).visitEnd();

cw.visitField(Opcodes.ACC_PUBLIC+Opcodes.ACC_FINAL+Opcodes.ACC_STATIC,

"EQUAL", "I", null, new Integer(0)).visitEnd();

cw.visitField(Opcodes.ACC_PUBLIC+Opcodes.ACC_FINAL+Opcodes.ACC_STATIC,

"GREATER", "I", null, new Integer(1)).visitEnd();

//定义类的方法

cw.visitMethod(Opcodes.ACC_PUBLIC+Opcodes.ACC_ABSTRACT, "compareTo",

"(Ljava/lang/Object;)I", null, null).visitEnd();

cw.visitEnd(); //使cw类已经完成

//将cw转换成字节数组写到文件里面去

byte[] data = cw.toByteArray();

File file = new File("D://Comparable.class");

FileOutputStream fout = new FileOutputStream(file);

fout.write(data);

fout.close();

}

}

生成一个类的字节码文件只需要用到ClassWriter类即可,生成Comparable.class后用javap指令对其进行反编译:javap -c Comparable.class >test.txt ,编译后的结果如下:public interface com.asm3.Comparable extends com.asm3.Mesurable {

public static final int LESS;

public static final int EQUAL;

public static final int GREATER;

public abstract int compareTo(java.lang.Object);

}

注:一个编译后的java类不包含package和import段,因此在class文件中所有的类型都使用的是全路径。

示例2.修改类的字节码文件

C.javapackage com.asm5;

public class C {

public void m() throws InterruptedException{

Thread.sleep(100);

}

}

将C.java类的内容改为如下:package com.asm5;

public class C {

public static long timer;

public void m() throws InterruptedException{

timer -= System.currentTimeMillis();

Thread.sleep(100);

timer += System.currentTimeMillis();

}

}

为了弄清楚ASM是如何实现的,我们先编译这两个类,然后比对它们的TraceClassVisitor的输出,我们可以发现如下的不同(粗体表示)

GETSTATIC C.timer : J

INVOKESTATIC java/lang/System.currentTimilis()J

LSUB

PUTSTATIC C.timer : J

LDC 100

INVOKESTATIC java/lang/Thread.sleep(J)V

GETSTATIC C.timer : J

INVOKESTATIC java/lang/System.currentTimilis()J

LADD

PUTSTATIC C.timer : J

RETURN

MAXSTACK=4

MAXLOCALS=1

通过比对上面的指令,我们可以发现必须在m()方法的最前面增加四条指令,在RETURN指令前也增加四条指令,同时这四条必须位于xRETURN和ATHROW之前,因为这些指令都会结束方法的执行。

具体代码如下:

AddTimeClassAdapter.javapackage com.asm5;

import org.objectweb.asm.ClassAdapter;

import org.objectweb.asm.ClassVisitor;

import org.objectweb.asm.FieldVisitor;

import org.objectweb.asm.MethodAdapter;

import org.objectweb.asm.MethodVisitor;

import org.objectweb.asm.Opcodes;

public class AddTimeClassAdapter extends ClassAdapter {

private String owner;

private boolean isInterface;

public AddTimeClassAdapter(ClassVisitor cv) {

super(cv);

}

@Override

public void visit(int version, int access, String name, String signature,

String superName, String[] interfaces) {

cv.visit(version, access, name, signature, superName, interfaces);

owner = name;

isInterface = (access & Opcodes.ACC_INTERFACE) != 0;

}

@Override

public MethodVisitor visitMethod(int access, String name, String desc,

String signature, String[] exceptions) {

MethodVisitor mv = cv.visitMethod(access, name, desc, signature, exceptions);

if(!name.equals("") && !isInterface && mv!=null){

//为方法添加计时功能

mv = new AddTimeMethodAdapter(mv);

}

return mv;

}

@Override

public void visitEnd() {

//添加字段

if(!isInterface){

FieldVisitor fv = cv.visitField(Opcodes.ACC_PUBLIC+Opcodes.ACC_STATIC, "timer", "J", null, null);

if(fv!=null){

fv.visitEnd();

}

}

cv.visitEnd();

}

class AddTimeMethodAdapter extends MethodAdapter{

public AddTimeMethodAdapter(MethodVisitor mv) {

super(mv);

}

@Override

public void visitCode() {

mv.visitCode();

mv.visitFieldInsn(Opcodes.GETSTATIC, owner, "timer", "J");

mv.visitMethodInsn(Opcodes.INVOKESTATIC, "java/lang/System", "currentTimeMillis", "()J");

mv.visitInsn(Opcodes.LSUB);

mv.visitFieldInsn(Opcodes.PUTSTATIC, owner, "timer", "J");

}

@Override

public void visitInsn(int opcode) {

if((opcode>=Opcodes.IRETURN && opcode<=Opcodes.RETURN) || opcode==Opcodes.ATHROW){

mv.visitFieldInsn(Opcodes.GETSTATIC, owner, "timer", "J");

mv.visitMethodInsn(Opcodes.INVOKESTATIC, "java/lang/System", "currentTimeMillis", "()J");

mv.visitInsn(Opcodes.LADD);

mv.visitFieldInsn(Opcodes.PUTSTATIC, owner, "timer", "J");

}

mv.visitInsn(opcode);

}

@Override

public void visitMaxs(int maxStack, int maxLocal) {

mv.visitMaxs(maxStack+4, maxLocal);

}

}

}

Generator.javapackage com.asm5;

import java.io.File;

import java.io.FileNotFoundException;

import java.io.FileOutputStream;

import java.io.IOException;

import org.objectweb.asm.ClassAdapter;

import org.objectweb.asm.ClassReader;

import org.objectweb.asm.ClassWriter;

public class Generator {

public static void main(String[] args){

try {

ClassReader cr = new ClassReader("com/asm5/C");

ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS);

ClassAdapter classAdapter = new AddTimeClassAdapter(cw);

//使给定的访问者访问Java类的ClassReader

cr.accept(classAdapter, ClassReader.SKIP_DEBUG);

byte[] data = cw.toByteArray();

File file = new File(System.getProperty("user.dir") + "\\WebRoot\\WEB-INF\\classes\\com\\asm5\\C.class");

FileOutputStream fout = new FileOutputStream(file);

fout.write(data);

fout.close();

System.out.println("success!");

} catch (FileNotFoundException e) {

e.printStackTrace();

} catch (IOException e) {

e.printStackTrace();

}

}

}

下面是一个测试类:package com.asm5;

public class Test {

public static void main(String[] args) throws InterruptedException, NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException {

C c = new C();

c.m();

Class cc = c.getClass();

System.out.println(cc.getField("timer").get(c));

}

}

输出结果为:100

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作能带来一定的帮助,如果有疑问大家可以留言交流。

更多java字节码框架ASM的深入学习相关文章请关注PHP中文网!

本文原创发布php中文网,转载请注明出处,感谢您的尊重!

java asm 教程_java字节码框架ASM的深入学习相关推荐

  1. Java字节码框架ASM简介

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

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

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

  3. java忍者_Java字节码忍者禁术

    Java语言本身是由Java语言规格说明(JLS)所定义的,而Java虚拟机的可执行字节码则是由一个完全独立的标准,即Java虚拟机规格说明(通常也被称为VMSpec)所定义的. JVM字节码是通过j ...

  4. java 魔数_Java 字节码结构解析

    本文通过解析Class文件中字节码的结构,来加深对Java类文件结构的理解.建议先阅读Java类文件结构解析这篇文章. Test.java package org.tianbin.clazz; pub ...

  5. 【JVM】字节码与ASM字节码增强、Instrument实现类的动态重加载

    目录 字节码与ASM字节码增强 什么是字节码? 字节码结构 操作数栈与字节码 字节码增强 ASM 运行时类加载 Instrument JPDA与JVMTI instrument实现热加载的过程 字节码 ...

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

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

  7. 从GraalVM到Quarkus系列-B002篇-Quarkus中的字节码框架gizmo

    从GraalVM到Quarkus系列 A000篇-忽悠你用GraalVM A001篇-NativeImage相关的注解 B001篇-NativeImage相关的注解@TargetClass A002篇 ...

  8. OpenRasp Java运行时修改字节码技术

    Java运行时修改字节码技术 Java运行时动态修改字节码技术,常用的有javassist asm来实现.不过最近在分析openrasp-java这块时,程序使用的javassist来动态插桩关键类, ...

  9. 尚硅谷 宋红康 JVM教程_02_字节码与类的加载篇

    本系列相关链接 尚硅谷 宋红康 JVM教程_01_内存与垃圾回收篇--01 (20210103-20210110) https://blog.csdn.net/wei198621/article/de ...

  10. java 执行字节码_深入理解java:1.2. 字节码执行引擎

    执行引擎是Java虚拟机的核心组成部分之一. 首先,想想C++和Java在编译和运行时到底有啥不一样? 下图左边,C++发布的就是机器指令, 而下图右边Java发布的是字节码,字节码在运行时通过JVM ...

最新文章

  1. 「AI初识境」被Hinton,DeepMind和斯坦福嫌弃的池化到底是什么?
  2. new和make的区别
  3. Linux 系统下命令 unrar 的英文版使用说明
  4. linux+if语句+break,linux——shell 中常用的控制语句 for、while、if、case、expect、exit、break、continue...
  5. 贾跃亭成了,FF 91预量产车下线完成
  6. mysql主从同步当天数据,mysql主从数据同步
  7. asp.net mvc 过滤器
  8. 【转载】VBA 读取EXCEL 行列总数
  9. python的os,commands,subprocess启动进程调用的几种方法
  10. 自定义添加的鼠标事件
  11. QT信号(signal)和槽(slot)问题
  12. Vscode C环境配置(转)
  13. 代谢组与微生物联合分析实战
  14. 51单片机倒计时蜂鸣器c语言,基于51单片机的倒计时器设计
  15. 相控阵天线方位角俯仰角matlab画图,理解相控阵天线的方向图
  16. 带壳破解SMC补丁技术
  17. 事务的四大特性-ADID特性
  18. 草图vr3.6许可证服务器安装失败,SU2018装Vray3.6出现这个是怎么回事啊
  19. 数学问题1 - 两个圆圈,小圆贴着大圆外部转过一圈,问小圆转几圈
  20. 如何查询一个IP上所绑定的域名

热门文章

  1. 国内自主研发的游戏引擎一览
  2. 手机怎么用外嵌字幕_iphone 12发布 ! “预购、定金、尾款、换手机”用英语怎么说?...
  3. wireshark抓包工具详细说明及操作使用
  4. 软件开发javascript html实现网页版日历代码_javascript技巧
  5. 【洛谷】P1216数字三角形
  6. 电源篇 -- 升压电路 Boost
  7. 最齐全的日用电商设计模板素材,速来收藏
  8. Android 融云SDK-即时通讯IM(附源码)
  9. 从小米摄像头事件,到物联网安全的“三重门”
  10. 求解汉诺塔问题(提示, 使用递归)