字节码技术可以动态改变某个类的结构(添加/删除/修改 新的属性/方法)
关于字节码的框架有javassist,asm,bcel等
引入依赖
<dependency> <groupId>javassist</groupId> <artifactId>javassist</artifactId> <version>3.12.1.GA</version> </dependency>
生成字节码
//创建字节码文件 public class CreateClass { public static void main(String[] args) throws CannotCompileException, NotFoundException, IOException { ClassPool pool = ClassPool.getDefault(); // 1.创建user类 CtClass userClass = pool.makeClass("com.irish.entity.User"); // 2.创建name 和age属性 CtField nameField = CtField.make("private String name;", userClass); CtField ageField = CtField.make("private Integer age;", userClass); // 3.添加属性 userClass.addField(nameField); userClass.addField(ageField); // 4.创建方法 CtMethod nameMethod = CtMethod.make("public String getName() {return name;}", userClass); // 5.添加方法 userClass.addMethod(nameMethod); // 6.添加构造函数 CtConstructor ctConstructor = new CtConstructor( new CtClass[] { pool.get("java.lang.String"), pool.get("java.lang.Integer") }, userClass); ctConstructor.setBody(" { this.name = name; this.age = age; }"); userClass.addConstructor(ctConstructor); // 生成class文件 userClass.writeFile("F:/test"); System.out.println("生成字节码,成功!"); } }
读取字节码后,对字节码新增方法,然后执行该方法
这里的User类要存在,UpdateClass 才可以读取出他的字节码后再修改
public class User { private String name; private Integer age; }
//动态修改字节码文件 public class UpdateClass { @SuppressWarnings({ "rawtypes", "unchecked" }) public static void main(String[] args) { try { ClassPool pool = ClassPool.getDefault(); // 读取com.irish.User CtClass userClass = pool.get("com.irish.User"); CtMethod method = new CtMethod(CtClass.voidType, "sum", new CtClass[] { CtClass.intType, CtClass.intType }, userClass); method.setBody("{System.out.println("sun:" + ($1 + $2));}"); // 添加方法 userClass.addMethod(method); //将修改后的字节码写入到磁盘中,通过反编译工具,可以看到对类进行了修改 userClass.writeFile("F:/test"); // 动态执行方法 Class clazz = userClass.toClass(); Object newInstance = clazz.newInstance(); Method sumMethod = clazz.getDeclaredMethod("sum", int.class, int.class); sumMethod.invoke(newInstance, 2, 5); } catch (Exception e) { e.printStackTrace(); } } }