asm字节码操作 方法的动态修改增加
2012-08-13 18:22
375 查看
asm 4.0 版本
http://forge.ow2.org/plugins/scmsvn/index.php?group_id=23
asm是java的字节码操作框架,可以动态查看类的信息,动态修改,删除,增加类的方法。
下面基于4.0版本的一个使用示例,演示了对类Foo进行修改方法名称,增加方法,修改方法内容等
输出:
add方法是新增的,execute方法名改为execute1,changeMethodContent方法修改后增加了输出this is a modify method!
我们把最终的字节码保存到文件中e:\\logs\\Example.class中,再用反编译工具java decompiler 查看最终的生成的源码:
最终的类如下:
接下来再慢慢研究asm里面对字节码的操作,还有其他框架是如果使用asm的。
http://forge.ow2.org/plugins/scmsvn/index.php?group_id=23
asm是java的字节码操作框架,可以动态查看类的信息,动态修改,删除,增加类的方法。
下面基于4.0版本的一个使用示例,演示了对类Foo进行修改方法名称,增加方法,修改方法内容等
import java.io.FileOutputStream; import java.io.IOException; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import org.objectweb.asm.ClassReader; import org.objectweb.asm.ClassVisitor; import org.objectweb.asm.ClassWriter; import org.objectweb.asm.MethodVisitor; import org.objectweb.asm.Opcodes; public class AsmExample extends ClassLoader implements Opcodes{ public static class Foo { public static void execute() { System.out.println("test changed method name"); } public static void changeMethodContent() { System.out.println("test change method"); } } public static void main(String[] args) throws IOException, IllegalArgumentException, SecurityException, IllegalAccessException, InvocationTargetException { ClassReader cr = new ClassReader(Foo.class.getName()); ClassWriter cw = new ClassWriter(cr, ClassWriter.COMPUTE_MAXS); ClassVisitor cv = new MethodChangeClassAdapter(cw); cr.accept(cv, Opcodes.ASM4); //新增加一个方法 MethodVisitor mw= cw.visitMethod(ACC_PUBLIC + ACC_STATIC, "add", "([Ljava/lang/String;)V", null, null); // pushes the 'out' field (of type PrintStream) of the System class mw.visitFieldInsn(GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;"); // pushes the "Hello World!" String constant mw.visitLdcInsn("this is add method print!"); // invokes the 'println' method (defined in the PrintStream class) mw.visitMethodInsn(INVOKEVIRTUAL, "java/io/PrintStream", "println", "(Ljava/lang/String;)V"); mw.visitInsn(RETURN); // this code uses a maximum of two stack elements and two local // variables mw.visitMaxs(0, 0); mw.visitEnd(); // gets the bytecode of the Example class, and loads it dynamically byte[] code = cw.toByteArray(); AsmExample loader = new AsmExample(); Class<?> exampleClass = loader.defineClass(Foo.class.getName(), code, 0, code.length); for(Method method: exampleClass.getMethods()){ System.out.println(method); } System.out.println("*************"); // uses the dynamically generated class to print 'Helloworld' exampleClass.getMethods()[0].invoke(null, null); //調用changeMethodContent,修改方法內容 System.out.println("*************"); exampleClass.getMethods()[1].invoke(null, null); //調用execute,修改方法名 // gets the bytecode of the Example class, and loads it dynamically FileOutputStream fos = new FileOutputStream("e:\\logs\\Example.class"); fos.write(code); fos.close(); } static class MethodChangeClassAdapter extends ClassVisitor implements Opcodes { public MethodChangeClassAdapter(final ClassVisitor cv) { super(Opcodes.ASM4, cv); } @Override public void visit( int version, int access, String name, String signature, String superName, String[] interfaces) { if (cv != null) { cv.visit(version, access, name, signature, superName, interfaces); } } @Override public MethodVisitor visitMethod( int access, String name, String desc, String signature, String[] exceptions) { if (cv != null && "execute".equals(name)) { //当方法名为execute时,修改方法名为execute1 return cv.visitMethod(access, name + "1", desc, signature, exceptions); } if("changeMethodContent".equals(name)) //此处的changeMethodContent即为需要修改的方法 ,修改方法內容 { MethodVisitor mv = cv.visitMethod(access, name, desc, signature, exceptions);//先得到原始的方法 MethodVisitor newMethod = null; newMethod = new AsmMethodVisit(mv); //访问需要修改的方法 return newMethod; } if (cv != null) { return cv.visitMethod(access, name, desc, signature, exceptions); } return null; } } static class AsmMethodVisit extends MethodVisitor { public AsmMethodVisit(MethodVisitor mv) { super(Opcodes.ASM4, mv); } @Override public void visitMethodInsn(int opcode, String owner, String name, String desc) { super.visitMethodInsn(opcode, owner, name, desc); } @Override public void visitCode() { //此方法在访问方法的头部时被访问到,仅被访问一次 //此处可插入新的指令 super.visitCode(); } @Override public void visitInsn(int opcode) { //此方法可以获取方法中每一条指令的操作类型,被访问多次 //如应在方法结尾处添加新指令,则应判断: if(opcode == Opcodes.RETURN) { // pushes the 'out' field (of type PrintStream) of the System class mv.visitFieldInsn(GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;"); // pushes the "Hello World!" String constant mv.visitLdcInsn("this is a modify method!"); // invokes the 'println' method (defined in the PrintStream class) mv.visitMethodInsn(INVOKEVIRTUAL, "java/io/PrintStream", "println", "(Ljava/lang/String;)V"); // mv.visitInsn(RETURN); } super.visitInsn(opcode); } } }
输出:
add方法是新增的,execute方法名改为execute1,changeMethodContent方法修改后增加了输出this is a modify method!
public static void AsmExample$Foo.changeMethodContent() public static void AsmExample$Foo.execute1() public static void AsmExample$Foo.add(java.lang.String[]) public native int java.lang.Object.hashCode() public final native java.lang.Class java.lang.Object.getClass() public final void java.lang.Object.wait(long,int) throws java.lang.InterruptedException public final void java.lang.Object.wait() throws java.lang.InterruptedException public final native void java.lang.Object.wait(long) throws java.lang.InterruptedException public boolean java.lang.Object.equals(java.lang.Object) public java.lang.String java.lang.Object.toString() public final native void java.lang.Object.notify() public final native void java.lang.Object.notifyAll() ************* test change method this is a modify method! ************* test changed method name
我们把最终的字节码保存到文件中e:\\logs\\Example.class中,再用反编译工具java decompiler 查看最终的生成的源码:
最终的类如下:
import java.io.PrintStream; public class AsmExample$Foo { public static void execute1() { System.out.println("test changed method name"); } public static void changeMethodContent() { System.out.println("test change method"); System.out.println("this is a modify method!"); } public static void add(String[] paramArrayOfString) { System.out.println("this is add method print!"); } }
接下来再慢慢研究asm里面对字节码的操作,还有其他框架是如果使用asm的。
相关文章推荐
- asm字节码操作 方法的动态修改增加
- asm字节码操作 方法的动态修改增加
- 动态增加、修改、删除URL参数方法
- JS中常用操作技巧(页面动态增加div,contain方法扩展,JSON对象鱼字符串转换)
- jqgrid 的一些操作 动态增加列 用本地 数据 修改表格
- javascript 动态修改css样式方法+JQuery中操作Css样式的方法
- C#—Dev XtraTabControl操作总结如动态增加Tab和关闭选项卡方法等
- js操作表格操方法,增加,修改,删除,一行记录
- C# 查询 增加 修改 删除 操作数据库方法
- 怎样在JAVA 中封装数据库操作(增删改查)运用反射机制!已贴出删除和查询方法,求增加和修改!
- vb.net操作注册表的方法分析【增加,修改,删除,查询】
- 用java实现的双向链表增加删除修改操作
- Spring实现动态修改时间参数并手动开启关停操作
- ASP.NET 操作session详解 增加,修改,删除
- AFN中所使用的 '运行时' 的交换类的方法和给类动态增加方法
- db2取前十条记录 db2修改字段长度 db2增加字段方法
- SQL SERVER不能修改表的解决方法(增加字段、修改字段名)
- 关于JQuery中的ajax请求或者post请求的回调方法中的操作执行或者变量修改没反映的问题
- 集插入,删除,修改一体的操作数据库数据的方法
- 动态修改Python类和实例的方法(转)