asm字节码操作 方法的动态修改增加

news/2024/7/7 7:21:42

asm 4.0 版本

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的。

转载于:https://www.cnblogs.com/secbook/archive/2012/08/13/2655146.html


http://www.niftyadmin.cn/n/4235157.html

相关文章

【C语言】—— 宏和枚举区别

文章目录 定义方式不同类型检查不同替换时机不同适用场景不同定义范围不同可读性可扩展性可移植性调试和错误处理编译器优化命名空间示例宏定义枚举 总结 C语言中&#xff0c;枚举和宏是两种不同的语法结构&#xff0c;用于定义常量或标识符。它们有以下区别&#xff1a; 枚举是…

left join 终极理解

left join 就是关联&#xff0c;右表多出来不相干 关联不上不要&#xff0c;右边少了以空代替&#xff0c;保证左表全出来&#xff0c;如果右边重复记录&#xff0c;则左表关联上部分也重复。总结就是&#xff0c;左表只会多(重复、因右表重复)不会少&#xff0c;右表关联不上则…

Silverlight应用整合

2019独角兽企业重金招聘Python工程师标准>>> 在企业应用系统中&#xff0c;企业客户不在满足于呆板的Portal、树形结构、数据堆积的表格和满屏的文字描述。企业客户越来越倡导用户体 验&#xff0c;Silverlight迎合了这种需求&#xff0c;实现了炫目的体验和丰富交互…

服务器架构之性能扩展-目录(1)

近期对linux和windows网络服务器的性能扩展和高级应用进行了系统性的学习&#xff0c;这里和大家分享一下&#xff0c;希望共同进步&#xff0c;我也希望我可以将这些知识在与大家的互动中得到进一步的升华&#xff0c;期待大家的共同参与第一章&#xff1a;大型web架构的设计第…

装Framework3.5后Web不正常

装Framework3.5后Web不正常 posted on 2012-08-15 16:24 銼銼 阅读(...) 评论(...) 编辑 收藏 转载于:https://www.cnblogs.com/cclovett/archive/2012/08/15/2640296.html

ABAP日期函数应用

ABAP日期函数应用 根据当前时间如何找到上月的第一天和最后一天&#xff1f;CALL FUNCTION FIMA_DATE_CREATE EXPORTING I_DATE SY-DATUM I_MONTHS -1 I_SET_LAST_DAY_OF_MONTH X …

VMware View是如何克服水土不服的?(Part I)

《晏子春秋》曰&#xff1a;&ldquo;橘生淮南则为橘&#xff0c;生于淮北则为枳&#xff0c;叶徒相似&#xff0c;其实味不同。所以然者何&#xff1f;水土异也&rdquo;。桌面虚拟化作为一款洋软件&#xff0c;要想在中国快速地开枝散叶&#xff0c;要过的第一关当数&…