参考文档: https://www.w3cschool.cn/article/35230124.html
Javassist 是一个使用非常广的字节码插装框架,几乎一大部分非入侵的全链路监控都是会选择使用这个框架。因为它不想ASM那样操作字节码导致风险,同时它的功能也非常齐全。另外,这个框架即可使用它所提供的方式直接编写插装代码,也可以使用字节码指令进行控制生成代码,所以综合来看也是一个非常不错的字节码框架。
引入依赖
<dependency>
<groupId>org.javassist</groupId>
<artifactId>javassist</artifactId>
<version>3.29.2-GA</version>
</dependency>
在 target/classes 路径下生成一个 Demo2.class
public class Demo1 {
public static void main(String[] args) throws NotFoundException, CannotCompileException, IOException, NoSuchMethodException {
URL resource = Demo1.class.getClassLoader().getResource("");
String file = resource.getFile();
System.out.println("文件存储路径: "+file); // 编译后的字节码文件存放目录
ClassPool pool = ClassPool.getDefault();
// 创建类
CtClass ctClass = pool.makeClass("com.shi.d2.Demo2");
// 创建属性
CtField ctField = new CtField(CtClass.longType,"id",ctClass);
ctField.setModifiers(Modifier.PRIVATE);
ctClass.addField(ctField,"3123121");
// 创建构造器
ctClass.addConstructor(CtNewConstructor.defaultConstructor(ctClass));
// 创建setter方法
ctClass.addMethod(CtNewMethod.setter("setId", ctField));
ctClass.addMethod(CtNewMethod.getter("getId", ctField));
// 1. 创建方法
// $0 $1 $2 对应栈帧中的局部变量表, 在实例方法中$0为this,在静态方法中没有this
CtMethod ctMethod = new CtMethod(CtClass.intType, "test", new CtClass[]{CtClass.intType, CtClass.intType}, ctClass);
ctMethod.setModifiers(Modifier.PUBLIC);
ctMethod.setBody("""
{
String s=new String("abc");
int i=s.indexOf(1);
System.out.println($0); // $0 this对象
return $1+$2;
}
""");
ctClass.addMethod(ctMethod);
// 2. 创建方法
CtMethod ctMethod1 = new CtMethod(CtClass.voidType, "test$args", new CtClass[]{CtClass.intType, CtClass.charType}, ctClass);
ctMethod1.setModifiers(Modifier.PUBLIC);
ctMethod1.setBody("""
{
Object[] objs=$args;
int nums=objs[0];
char c=objs[1];
}
""");
ctClass.addMethod(ctMethod1);
// 写入文件
ctClass.writeFile(file);
}
}
Demo2.class
public class Demo2 {
private long id = 3123121;
public Demo2() {
}
public void setId(long var1) {
this.id = var1;
}
public long getId() {
return this.id;
}
public int test(int var1, int var2) {
String var3 = new String("abc");
int var4 = var3.indexOf(1);
System.out.println(this);
return var1 + var2;
}
public void test$args(int var1, char var2) {
Object[] var3 = new Object[]{new Integer(var1), new Character(var2)};
Object var4 = var3[0];
char var5 = (char)var3[1];
}
}