ASM动态操作方法(增改)

2024-02-13 04:32
文章标签 动态 操作方法 asm 增改

本文主要是介绍ASM动态操作方法(增改),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

下面基于4.2版本的一个使用示例,演示了对类Foo进行修改方法名称,增加方法,修改方法内容等

package myASM;public class Foo {public  void execute(){System.out.println("test changed method name");}public  void changeMethodContent(){System.out.println("test changed method");}
}

 

package myASM;import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;public class MethodChangeClassAdapter extends ClassVisitor implements Opcodes{public MethodChangeClassAdapter(ClassVisitor cv) {super(Opcodes.ASM4, cv);}@Overridepublic 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);}}@Overridepublic MethodVisitor visitMethod(int access, String name, String desc,String signature, String[] exceptions) {//当方法名为execute时,修改方法名为execute1if (cv != null && "execute".equals(name)){return cv.visitMethod(access, name + "1", desc, signature, exceptions);}//此处的changeMethodContent即为需要修改的方法  ,修改方法內容if("changeMethodContent".equals(name)){//先得到原始的方法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;}
}

 

package myASM;import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;public class AsmMethodVisit extends MethodVisitor{public AsmMethodVisit(MethodVisitor mv) {super(Opcodes.ASM4, mv);}@Overridepublic void visitMethodInsn(int opcode, String owner, String name,String desc) {super.visitMethodInsn(opcode, owner, name, desc); }@Overridepublic void visitCode(){//此方法在访问方法的头部时被访问到,仅被访问一次  //此处可插入新的指令  super.visitCode();}@Overridepublic void visitInsn(int opcode){//此方法可以获取方法中每一条指令的操作类型,被访问多次  //如应在方法结尾处添加新指令,则应判断:if(opcode == Opcodes.RETURN){// pushes the 'out' field (of type PrintStream) of the System class mv.visitFieldInsn(Opcodes.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(Opcodes.INVOKEVIRTUAL, "java/io/PrintStream", "println", "(Ljava/lang/String;)V");}super.visitInsn(opcode);}
}

 

package myASM;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 void main(String args[]) throws IOException, IllegalArgumentException, SecurityException, IllegalAccessException, InvocationTargetException, InstantiationException{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);mw.visitFieldInsn(GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;");mw.visitLdcInsn("this is add method print!");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();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'//調用changeMethodContent,修改方法內容exampleClass.getMethods()[1].invoke(exampleClass.newInstance(), null);System.out.println("***************************");//調用execute,修改方法名 exampleClass.getMethods()[2].invoke(exampleClass.newInstance(), null); // gets the bytecode of the Example class, and loads it dynamically  FileOutputStream fos = new FileOutputStream("e:\\logs\\Example.class");  fos.write(code);  fos.close();}}

 最后在eclipse控制台输出结果:

 

public static void myASM.Foo.add(java.lang.String[])
public void myASM.Foo.changeMethodContent()
public void myASM.Foo.execute1()
public final native void java.lang.Object.wait(long) throws java.lang.InterruptedException
public final void java.lang.Object.wait() throws java.lang.InterruptedException
public final void java.lang.Object.wait(long,int) throws java.lang.InterruptedException
public boolean java.lang.Object.equals(java.lang.Object)
public java.lang.String java.lang.Object.toString()
public native int java.lang.Object.hashCode()
public final native java.lang.Class java.lang.Object.getClass()
public final native void java.lang.Object.notify()
public final native void java.lang.Object.notifyAll()
***************************
test changed method
this is a modify method!
***************************
test changed method name

 

然后通过反编译软件,查看E盘生成的Example.class

 

package myASM;import java.io.PrintStream;public class Foo
{public Foo(){}public void execute1(){System.out.println("test changed method name");}public void changeMethodContent(){System.out.println("test changed method");System.out.println("this is a modify method!");}public static void add(String as[]){System.out.println("this is add method print!");}
}

 

这篇关于ASM动态操作方法(增改)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/704483

相关文章

Java数组动态扩容的实现示例

《Java数组动态扩容的实现示例》本文主要介绍了Java数组动态扩容的实现示例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧... 目录1 问题2 方法3 结语1 问题实现动态的给数组添加元素效果,实现对数组扩容,原始数组使用静态分配

MyBatis-Plus使用动态表名分表查询的实现

《MyBatis-Plus使用动态表名分表查询的实现》本文主要介绍了MyBatis-Plus使用动态表名分表查询,主要是动态修改表名的几种常见场景,文中通过示例代码介绍的非常详细,对大家的学习或者工作... 目录1. 引入依赖2. myBATis-plus配置3. TenantContext 类:租户上下文

Java中的随机数生成案例从范围字符串到动态区间应用

《Java中的随机数生成案例从范围字符串到动态区间应用》本文介绍了在Java中生成随机数的多种方法,并通过两个案例解析如何根据业务需求生成特定范围的随机数,本文通过两个实际案例详细介绍如何在java中... 目录Java中的随机数生成:从范围字符串到动态区间应用引言目录1. Java中的随机数生成基础基本随

基于Nacos实现SpringBoot动态定时任务调度

《基于Nacos实现SpringBoot动态定时任务调度》本文主要介绍了在SpringBoot项目中使用SpringScheduling实现定时任务,并通过Nacos动态配置Cron表达式实现任务的动... 目录背景实现动态变更定时机制配置化 cron 表达式Spring schedule 调度规则追踪定时

springBoot (springCloud2025)集成redisCluster 集群的操作方法

《springBoot(springCloud2025)集成redisCluster集群的操作方法》文章介绍了如何使用SpringBoot集成RedisCluster集群,并详细说明了pom.xm... 目录pom.XMLapplication.yamlcluster配置类其他配置类连接池配置类Redis

Spring Gateway动态路由实现方案

《SpringGateway动态路由实现方案》本文主要介绍了SpringGateway动态路由实现方案,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随... 目录前沿何为路由RouteDefinitionRouteLocator工作流程动态路由实现尾巴前沿S

Python 常用数据类型详解之字符串、列表、字典操作方法

《Python常用数据类型详解之字符串、列表、字典操作方法》在Python中,字符串、列表和字典是最常用的数据类型,它们在数据处理、程序设计和算法实现中扮演着重要角色,接下来通过本文给大家介绍这三种... 目录一、字符串(String)(一)创建字符串(二)字符串操作1. 字符串连接2. 字符串重复3. 字

Python动态处理文件编码的完整指南

《Python动态处理文件编码的完整指南》在Python文件处理的高级应用中,我们经常会遇到需要动态处理文件编码的场景,本文将深入探讨Python中动态处理文件编码的技术,有需要的小伙伴可以了解下... 目录引言一、理解python的文件编码体系1.1 Python的IO层次结构1.2 编码问题的常见场景二

Java使用Javassist动态生成HelloWorld类

《Java使用Javassist动态生成HelloWorld类》Javassist是一个非常强大的字节码操作和定义库,它允许开发者在运行时创建新的类或者修改现有的类,本文将简单介绍如何使用Javass... 目录1. Javassist简介2. 环境准备3. 动态生成HelloWorld类3.1 创建CtC

python urllib模块使用操作方法

《pythonurllib模块使用操作方法》Python提供了多个库用于处理URL,常用的有urllib、requests和urlparse(Python3中为urllib.parse),下面是这些... 目录URL 处理库urllib 模块requests 库urlparse 和 urljoin编码和解码