Javassist:使用-javaagent方式实现修改方法内容(打包和非打包方式执行)
Posted 你是小KS
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Javassist:使用-javaagent方式实现修改方法内容(打包和非打包方式执行)相关的知识,希望对你有一定的参考价值。
1. 声明
当前内容主要为使用Javassit+(-javaagent)方式实现修改方法体的内容(不修改源码的情况下)
当前内容参考:Javassit官方文档,和部分反编译
主要内容:
- 使用javassit修改某个类的某个方法,实现执行
- 打成jar包方式执行
pom依赖
<dependency>
<groupId>org.javassist</groupId>
<artifactId>javassist</artifactId>
<version>3.27.0-GA</version>
</dependency>
2. 主要demo
1.实体类
public class User {
private Integer id;
private String username;
private Date birth;
// 省略get\\set\\toString\\无参\\有参
public String getSchoolName(Integer id) {
System.out.println("当前id=" + id);
return "A中学";
}
}
目标为修改getSchoolName的执行内容
2.主要main函数
public class MyJavaAssigentTest {
public static void main(String[] args) {
User user = new User(1, "张三", new Date());
String schoolName = user.getSchoolName(1);
System.out.println("当前的schoolName=" + schoolName);
System.out.println("");
}
}
一个非常简单的获取
3.主要javaAssigent类
import java.io.IOException;
import java.lang.instrument.ClassFileTransformer;
import java.lang.instrument.IllegalClassFormatException;
import java.lang.instrument.Instrumentation;
import java.security.ProtectionDomain;
import javassist.CannotCompileException;
import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtMethod;
import javassist.NotFoundException;
/**
*
* @author hy
* @createTime 2021-06-19 13:15:43
* @description 定义自己的javaassigent来实现在加载的时候修改加载后的字节码
*
*/
public class MyJavaAssigent {
public static void premain(String args, Instrumentation instrumentation) {
MyClassFileTransformer transformer = new MyClassFileTransformer();
instrumentation.addTransformer(transformer);
}
public static class MyClassFileTransformer implements ClassFileTransformer {
@Override
public byte[] transform(ClassLoader loader, String className, Class<?> classBeingRedefined,
ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException {
// 开始处理当前User类的getSchoolName方法,让其显示并返回数据
// System.out.println("已加载:" + className);
String modifyClassName="com.hy.vmopt.User";
String modifyClassMethod="getSchoolName";
String loadClassName=modifyClassName.replace(".", "/");
// 表示找到了这个类
if(loadClassName.equals(className)) {
// 开始使用当前的javassist修改字节码文件
try {
ClassPool pool = ClassPool.getDefault();
CtClass cc = pool.get(modifyClassName);
CtMethod declaredMethod = cc.getDeclaredMethod(modifyClassMethod);
// $1表示的就是第一个参数id
declaredMethod.setBody("{System.out.println(\\"hello insert\\");"
+ "$1=Integer.valueOf(6666);"
+ "System.out.println(\\"当前id=\\" + $1);" +
"return \\"A中学\\";}");
cc.detach();
return cc.toBytecode();
} catch (NotFoundException | CannotCompileException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
return classfileBuffer;
}
}
}
这里的transform的className是xxx/xxx/xxx的形式
,而javassist是xxx.xxx.xxx的形式
这里需要注意的是:
$1表示第一个参数,其他的以此类推,注意$0就是this
使用赋值语句的时候需要使用Integer.valueOf方式转化(这个部分需要参考反编译jd-gui)
- 使用setBody时一定要使用
{}
,否则加载字节码时报错
3. 开始非打包方式执行(javaagent需要打包)
1.具体的javaagent打包参考:博文
2.具体配置vm参数参考:博文
3.开始执行:
这个可以执行(原因:当前的pom依赖中具有javassist的库,所以可以执行)
4. 将两个包一起执行(命令行执行)
1.将具有javaagent的类的打包(并具有lib库),参考:博文
2.将具有main方法的类打包(空包),参考:博文
打包和修改后如下
其中myAssigent.jar中具有lib库的依赖,myUserTest.jar是main方法的jar
最后执行:
java -javaagent:myAssigent.jar -jar myUserTest.jar
直接执行成功!
以上是关于Javassist:使用-javaagent方式实现修改方法内容(打包和非打包方式执行)的主要内容,如果未能解决你的问题,请参考以下文章