ASM可以在字节层面修改.class文件,以此来修改一些类的行为。
首先导入asm的jar包(http://mirrors.ibiblio.org/pub/mirrors/maven2/asm/asm/3.2/asm-3.2.jar)
GeneralClassAdapter.java 主要用来拦截(代理)要修改的方法,并修改:
[java]
package com.znn.mv;
import org.objectweb.asm.ClassAdapter;
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.MethodAdapter;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.Type;
public class GeneralClassAdapter extends ClassAdapter {
public GeneralClassAdapter(ClassVisitor cv) {
super(cv);
}
@Override
public MethodVisitor visitMethod(int access, String name, String desc,
String signature, String[] exceptions) {
MethodVisitor mv = cv.visitMethod(access, name, desc, signature,
exceptions);
// 当是sayName方法是做对应的修改
if (name.equals("sayHello")) {
MethodVisitor newMv = new SayNameMethodAdapter(mv);
return newMv;
} else {
return mv;
}
}
// 定义一个自己的方法访问类
class SayNameMethodAdapter extends MethodAdapter {
public SayNameMethodAdapter(MethodVisitor mv) {
super(mv);
}
// 在源方法前去修改方法内容,这部分的修改将加载源方法的字节码之前
@Override
public void visitCode() {
// 记载隐含的this对象,这是每个JAVA方法都有的
mv.visitVarInsn(Opcodes.ALOAD, 0);
// 从常量池中加载“zhangzhuo”字符到栈顶
mv.visitLdcInsn("Zhangningning");
// 将栈顶的"zhangzhuo"赋值给name属性
mv.visitFieldInsn(Opcodes.PUTFIELD,
Type.getInternalName(Person.class), "name",
Type.getDescriptor(String.class));
}
}
}
[/java]
GenerateNewPerson.java 加载.class文件执行修改<p/>
[java]
package com.znn.mv;
import java.io.File;
import java.io.FileOutputStream;
import org.objectweb.asm.ClassAdapter;
import org.objectweb.asm.ClassReader;
import org.objectweb.asm.ClassWriter;
public class GenerateNewPerson {
public static void main(String[] args) throws Exception {
// 使用全限定名,创建一个ClassReader对象
// Person person = new Person();
// person.sayName();
ClassReader classReader = new ClassReader(
"com.znn.mv.Person");
// 构建一个ClassWriter对象,并设置让系统自动计算栈和本地变量大小
ClassWriter classWriter = new ClassWriter(ClassWriter.COMPUTE_MAXS);
ClassAdapter classAdapter = new GeneralClassAdapter(classWriter);
classReader.accept(classAdapter, ClassReader.SKIP_DEBUG);
byte[] classFile = classWriter.toByteArray();
// 将这个类输出到原先的类文件目录下,这是原先的类文件已经被修改
File file = new File(
"bin/com/znn/mv/Person.class");
FileOutputStream stream = new FileOutputStream(file);
// File f = new File("");
// System.out.println(f.getAbsolutePath());
stream.write(classFile);
stream.close();
// Person person = new Person();
// person.sayName();
System.out.println("Modify finish…");
}
}
[/java]
Person.java
[java]
package com.znn.mv;
public class Person {
private String name;
public void sayHello() {
System.out.println("Hello,"+name);
}
}
[/java]
测试类:Test.java
[java]
package com.znn.mv;
public class Test {
public static void main(String[] args) {
Person person = new Person();
person.sayHello();
}
}
[/java]
测试方法:
1.clean工程,重新编译
2.执行Test.java
null默认为空
3.执行GenerateNewPerson.java,将name的值改成zhangningning
4.再次执行Test.java
转载请注明:Z/RANDY » 使用ASM修改一个.class文件