字节码类库之Javassist
Javassist优势
– 比反射开销小,性能高。
–javassist性能高于反射,低于ASM
运行时操作字节码可以让我们实现如下功能:
– 动态生成 新的类
– 动态改变某个类的结构 ( 添加 / 删除 / 修改 新的属性 / 方法 )
javassist 的最外层的 API 和 JAVA 的反射包中的 API 颇为 类似 。
它 主要 由 CtClass , CtMethod, ,以及 CtField 几个类组成。用以执行和 JDK 反射 API 中 java.lang.Class, java.lang.reflect.Method, java.lang.reflect.Method .Field 相同的 操作 。
方法操作
– 修改已有方法的方法体(插入代码到已有方法体)
– 新增方法 删除方法
javassist的局限性
JDK5.0 新语法不支持 ( 包括泛型、枚举 ) ,不支持注解修改,但可以通过底层的 javassist 类来解决,具体参考: javassist.bytecode.annotation
不支持数组的初始化,如 String[]{"1","2"} ,除非只有数组的容量为 1
不支持内部类和匿名类
不支持 continue 和 break表达式。
对于继承关系,有些不支持。例如
class A {}
class B extends A {}
class C extends B {}
创建类:
import javassist.ClassPool; import javassist.CtClass; import javassist.CtConstructor; import javassist.CtField; import javassist.CtMethod; import javassist.CtNewConstructor; public class App { public static void main(String[] args) throws Exception { // 利用javassist 创建类 ClassPool poll = ClassPool.getDefault(); // 创建类名 全路径 CtClass ctClass = poll.makeClass("com.hella.thread.jvm.javassist.User"); // 创建属性 CtField name = CtField.make("private String name;", ctClass); CtField age = CtField.make("private String age;", ctClass); // 属性添加到类中 ctClass.addField(name); ctClass.addField(age); // 创建get set 方法 CtMethod getName = CtMethod.make("public void getName(){return name;}", ctClass); CtMethod setName = CtMethod.make("public void setName(String name) {this.name = name;}", ctClass); CtMethod getAge = CtMethod.make("public String getAge() {return age;}", ctClass); CtMethod setAge = CtMethod.make("public void setAge(String age) {this.age = age;}", ctClass); // 方法添加到类中 ctClass.addMethod(getName); ctClass.addMethod(setName); ctClass.addMethod(getAge); ctClass.addMethod(setAge); // 创建构造方法 CtConstructor constructor = CtNewConstructor .make("public User(String name, String age) { this.name = name;this.age = age;}", ctClass); ctClass.addConstructor(constructor); // 生成的位置 ctClass.writeFile("C:/Users/caich5/Desktop/test"); } }
修改类的信息
public class User { private String name; private String age; // 通过字节码技术,在这个类添加以下的方法 // public int calcute(int a,int b){ // return a + b; // } }
修改并且执行:
import java.lang.reflect.Method; import javassist.ClassPool; import javassist.CtClass; import javassist.CtMethod; public class Test { public static void main(String[] args) throws Exception { ClassPool poll = ClassPool.getDefault(); // 获取到class CtClass ctClass = poll.get("com.hella.thread.jvm.javassist.User"); CtMethod ctMethod = CtMethod.make("public int calcute(int a,int b){ return a + b ;}", ctClass); ctClass.addMethod(ctMethod); ctClass.writeFile("C:/Users/caich5/Desktop/test"); // 使用反射执行 Class<?> clazz = ctClass.toClass(); Object newInstance = clazz.newInstance(); Method method = clazz.getDeclaredMethod("calcute", int.class, int.class); Object res = method.invoke(newInstance, 1, 2); System.out.println(res); // 需要添加的方法 也可以这样写 // CtMethod m = new CtMethod(CtClass.intType, "add", new CtClass[] { // CtClass.intType, CtClass.intType }, // userClass); // // 方法权限 // m.setModifiers(Modifier.PUBLIC); // // 方法体内容 // m.setBody("{System.out.println(\"Test003\"); return $1+$2;}"); } }
Aimer,c'est partager