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

相关文章

Golang 日志处理和正则处理的操作方法

《Golang日志处理和正则处理的操作方法》:本文主要介绍Golang日志处理和正则处理的操作方法,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考... 目录1、logx日志处理1.1、logx简介1.2、日志初始化与配置1.3、常用方法1.4、配合defer

Java调用C#动态库的三种方法详解

《Java调用C#动态库的三种方法详解》在这个多语言编程的时代,Java和C#就像两位才华横溢的舞者,各自在不同的舞台上展现着独特的魅力,然而,当它们携手合作时,又会碰撞出怎样绚丽的火花呢?今天,我们... 目录方法1:C++/CLI搭建桥梁——Java ↔ C# 的“翻译官”步骤1:创建C#类库(.NET

MyBatis编写嵌套子查询的动态SQL实践详解

《MyBatis编写嵌套子查询的动态SQL实践详解》在Java生态中,MyBatis作为一款优秀的ORM框架,广泛应用于数据库操作,本文将深入探讨如何在MyBatis中编写嵌套子查询的动态SQL,并结... 目录一、Myhttp://www.chinasem.cnBATis动态SQL的核心优势1. 灵活性与可

Mybatis嵌套子查询动态SQL编写实践

《Mybatis嵌套子查询动态SQL编写实践》:本文主要介绍Mybatis嵌套子查询动态SQL编写方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录前言一、实体类1、主类2、子类二、Mapper三、XML四、详解总结前言MyBATis的xml文件编写动态SQL

SpringBoot实现Kafka动态反序列化的完整代码

《SpringBoot实现Kafka动态反序列化的完整代码》在分布式系统中,Kafka作为高吞吐量的消息队列,常常需要处理来自不同主题(Topic)的异构数据,不同的业务场景可能要求对同一消费者组内的... 目录引言一、问题背景1.1 动态反序列化的需求1.2 常见问题二、动态反序列化的核心方案2.1 ht

golang实现动态路由的项目实践

《golang实现动态路由的项目实践》本文主要介绍了golang实现动态路由项目实践,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习... 目录一、动态路由1.结构体(数据库的定义)2.预加载preload3.添加关联的方法一、动态路由1

Spring Boot项目打包和运行的操作方法

《SpringBoot项目打包和运行的操作方法》SpringBoot应用内嵌了Web服务器,所以基于SpringBoot开发的web应用也可以独立运行,无须部署到其他Web服务器中,下面以打包dem... 目录一、打包为JAR包并运行1.打包为可执行的 JAR 包2.运行 JAR 包二、打包为WAR包并运行

Python Selenium动态渲染页面和抓取的使用指南

《PythonSelenium动态渲染页面和抓取的使用指南》在Web数据采集领域,动态渲染页面已成为现代网站的主流形式,本文将从技术原理,环境配置,核心功能系统讲解Selenium在Python动态... 目录一、Selenium技术架构解析二、环境搭建与基础配置1. 组件安装2. 驱动配置3. 基础操作模

Linux搭建单机MySQL8.0.26版本的操作方法

《Linux搭建单机MySQL8.0.26版本的操作方法》:本文主要介绍Linux搭建单机MySQL8.0.26版本的操作方法,本文通过图文并茂的形式给大家讲解的非常详细,感兴趣的朋友一起看看吧... 目录概述环境信息数据库服务安装步骤下载前置依赖服务下载方式一:进入官网下载,并上传到宿主机中,适合离线环境

慢sql提前分析预警和动态sql替换-Mybatis-SQL

《慢sql提前分析预警和动态sql替换-Mybatis-SQL》为防止慢SQL问题而开发的MyBatis组件,该组件能够在开发、测试阶段自动分析SQL语句,并在出现慢SQL问题时通过Ducc配置实现动... 目录背景解决思路开源方案调研设计方案详细设计使用方法1、引入依赖jar包2、配置组件XML3、核心配