`

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

 
阅读更多

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

1
3
分享到:
评论

相关推荐

    ASM字节码操作简单实例

    一个简单的通过ASM修改字节码实现AOP功能的实例,简单易懂,可运行...

    ASM操作字节码,动态生成Java类class文件

    ASM操作字节码,动态生成Java类class文件,模拟Spring的AOP实现原理。

    ASM 字节码修改工具中文帮助手册

    ASM 4 的中文文档 网上的博文都是从这上边摘得,大家下载下来学学就会了,这个是最全的了。我就是通过这个学会的。

    asm操作指南(中文)

    ASM是一个java字节码操纵框架,它能被用来动态...asm字节码增强技术主要是用来反射的时候提升性能的,如果单纯用jdk的反射调用,性能是非常低下的,而使用字节码增强技术后反射调用的时间已经基本可以与直接调用相当了

    Java字节码操纵框架 asm-3.1组件包大集合

    Java class 被存储在严格格式定义的 .class 文件里,这些类文件拥有足够的元数据来解析类中的所有元素:类名称、方法、属性以及 Java 字节码(指令)。ASM 从类文件中读入信息后,能够改变类行为,分析类信息,甚至...

    Javassist 修改class字节码

    Javassist 提供了java类库,用于方便操控Java字节码。功能包括:运行时创建java class,修改class。与其他同类工具(asm等)...通过java代码层,开发者即时对字节码不是很熟悉,也可以非常方便快速的完成字节码的修改。

    ASM 4 Guide 中文版

    在ASM中提供了诸多的API用于对类的内容进行字节码操作的方法。与传统的BCEL和SERL不同,在ASM中提供了更为优雅和灵活的操作字节码的方式。ASM相当小巧,并且它有更高的执行效率,是BCEL的7倍,SERP的11倍以上。目前...

    ASM4使用指南

    ASM是一个通用的Java字节码操作和分析框架。它可以用于修改现有类或直接以二进制形式动态生成类。ASM提供了一些常见的字节码转换和分析算法,可以从中构建自定义复杂转换和代码分析工具。ASM提供与其他Java字节码...

    asm4-guide.pdf

    Java的asm文档,来自官方。asm4-guide.pdf。ASM 是一个 Java 字节码操控框架。它能被用来动态生成类或者增强既有类的功能。ASM 可以直接产生二进制 class 文件,也可以在...说白了asm是直接通过字节码来修改class文件。

    asm5.0安装包

    ASM是一套java字节码生成架构,它可以动态生成二进制格式的stub类或其它代理类, 或者在类被java虚拟机装入内存之前,动态修改类。 现在挺多流行的框架都使用到了asm.所以从aop追溯来到了这。

    asm-commons-3.3.1.jar

    这可以通过操作方法的元数据(如方法名、返回类型、参数类型等)和字节码指令来实现。 4. 创建和修改字段:可以在运行时动态创建新的字段,或者修改现有的字段。这可以通过操作字段的元数据(如字段名、类型、修饰符...

    asm 最新版手册

    Java class 被存储在严格格式定义的 .class 文件里,这些类文件拥有足够的元数据来解析类中的所有元素:类名称、方法、属性以及 Java 字节码(指令)。ASM 从类文件中读入信息后,能够改变类行为,分析类信息,甚至...

    asm-tree-3.3.1.jar

    例如,可以使用ASM Tree API遍历一个类的整个字节码结构,查找并修改特定的指令或属性,或者在运行时动态生成新的类和方法。此外,由于ASM Tree API具有较高的抽象层次,因此它适用于各种类型的Java字节码操作,无论...

    Java字节码操作类库,基于这个api标准完成一个新的asmsupport实现

    asmsupport是一个字节码操作类库,它能够让程序员非常简单的在动态创建和修改类,该框架是基于asm开发的,不同与asm的是,它避免了直接操作jvm指令,栈和局部变量。这个模块包含了asmsupport使用的第三方依赖包的...

    ASM4中文使用指南.zip

    Java class 被存储在严格格式定义的 .class 文件里,这些类文件拥有足够的元数据来解析类中的所有元素:类名称、方法、属性以及 Java 字节码(指令)。ASM 从类文件中读入信息后,能够改变类行为,分析类信息,甚至...

    asm-9.0.jar

    ASM是一个java字节码操纵框架,它能被用来动态生成类或者增强既有类的功能。ASM 可以直接产生二进制 class 文件,也可以在类被加载入 Java 虚拟机之前动态改变类行为。Java class 被存储在严格格式定义的 .class文件...

    asm-master.zip

    ASM是一个通用的Java字节码操作和分析框架。 它可以用于修改现有类或直接以二进制形式动态生成类。 ASM提供了一些常见的字节码转换和分析算法,可以从中构建自定义复杂转换和代码分析工具。 ASM提供与其他Java字节码...

    asm4.1 jar+demo+doc

    Java class 被存储在严格格式定义的 .class 文件里,这些类文件拥有足够的元数据来解析类中的所有元素:类名称、方法、属性以及 Java 字节码(指令)。ASM 从类文件中读入信息后,能够改变类行为,分析类信息,甚至...

    asm5.0 源码+demo+doc

    Java class 被存储在严格格式定义的 .class 文件里,这些类文件拥有足够的元数据来解析类中的所有元素:类名称、方法、属性以及 Java 字节码(指令)。ASM 从类文件中读入信息后,能够改变类行为,分析类信息,甚至...

    ASMTools6.0字节码汇编反汇编修改工具最新版

    AsmTools项目是一个字节码分析和测试工具,用来生成正确的或者不正确的java .class文件,主要用来测试和验证。 我们知道直接修改.class文件是很麻烦的,虽然有一些图形界面的工具,但还是很麻烦。 通过ASMTools可以...

Global site tag (gtag.js) - Google Analytics