javassist实例
我们常用到的动态特性主要是反射,在运行时查找对象属性、方法,修改作用域,通过方法名称调用方法等。在线的应用不会频繁使用反射,因为反射的性能开销较大。其实还有一种和反射一样强大的特性,但是开销却很低,它就是Javassist。
Javassist其实就是一个二方包,提供了运行时操作Java字节码的方法。Java代码编译完会生成.class文件,就是一堆字节码。JVM(准确说是JIT)会解释执行这些字节码(转换为机器码并执行),由于字节码的解释执行是在运行时进行的,那我们能否手工编写字节码,再由JVM执行呢?答案是肯定的,而Javassist就提供了一些方便的方法,让我们通过这些方法生成字节码。
重要的类:
ClassPool:javassist的类池,使用ClassPool 类可以跟踪和控制所操作的类,它的工作方式与 JVM 类装载器非常相似,
CtClass: CtClass提供了检查类数据(如字段和方法)以及在类中添加新字段、方法和构造函数、以及改变类、父类和接口的方法。不过,Javassist 并未提供删除类中字段、方法或者构造函数的任何方法。
CtField:用来访问域
CtMethod :用来访问方法
CtConstructor:用来访问构造器
实例:
Example1:
1 public class Example1 { 2 public static void main(String[] args) throws Exception { 3 ClassPool pool = ClassPool.getDefault(); 4 CtClass cc = pool.makeClass("bean.User"); 5 6 //创建属性 7 CtField field01 = CtField.make("private int id;",cc); 8 CtField field02 = CtField.make("private String name;", cc); 9 cc.addField(field01); 10 cc.addField(field02); 11 12 //创建方法 13 CtMethod method01 = CtMethod.make("public String getName(){return name;}", cc); 14 CtMethod method02 = CtMethod.make("public void setName(String name){this.name = name;}", cc); 15 cc.addMethod(method01); 16 cc.addMethod(method02); 17 18 //添加有参构造器 19 CtConstructor constructor = new CtConstructor(new CtClass[]{CtClass.intType, pool.get("java.lang.String")}, cc); 20 constructor.setBody("{this.id=id;this.name=name;}"); 21 cc.addConstructor(constructor); 22 //无参构造器 23 CtConstructor cons = new CtConstructor(null, cc); 24 cons.setBody("{}"); 25 cc.addConstructor(cons); 26 27 cc.writeFile("E:/workspace/TestCompiler/src"); 28 } 29 }
Person:
1 public class Person { 2 3 public Person() {} 4 5 public Person(int id, String name) { 6 this.id = id; 7 this.name = name; 8 } 9 10 private int id; 11 12 private String name; 13 14 public int getId() { 15 return id; 16 } 17 18 public void setId(int id) { 19 this.id = id; 20 } 21 22 public String getName() { 23 return name; 24 } 25 26 public void setName(String name) { 27 this.name = name; 28 } 29 30 public String hello(String name) { 31 return name; 32 } 33 34 }
Example2:
1 public class Example2 { 2 3 //获取类的简单信息 4 public static void test01() throws Exception{ 5 ClassPool pool = ClassPool.getDefault(); 6 CtClass cc = pool.get("com.code.javassistdemo.example.Person"); 7 //得到字节码 8 byte[] bytes = cc.toBytecode(); 9 System.out.println(Arrays.toString(bytes)); 10 System.out.println(cc.getName());//获取类名 11 System.out.println(cc.getSimpleName());//获取简要类名 12 System.out.println(cc.getSuperclass());//获取父类 13 System.out.println(cc.getInterfaces());//获取接口 14 System.out.println(cc.getMethods());//获取 15 } 16 //新生成一个方法 17 public static void test02() throws Exception{ 18 ClassPool pool = ClassPool.getDefault(); 19 CtClass cc = pool.get("com.code.javassistdemo.example.Person"); 20 //第一种 21 //CtMethod cm = CtMethod.make("public String getName(){return name;}", cc); 22 //第二种 23 //参数:返回值类型,方法名,参数,对象 24 CtMethod cm = new CtMethod(CtClass.intType,"add", new CtClass[]{CtClass.intType, CtClass.intType}, cc); 25 cm.setModifiers(Modifier.PUBLIC);//访问范围 26 cm.setBody("{return $1+$2;}"); 27 //cc.removeMethod(m) 删除一个方法 28 cc.addMethod(cm); 29 //通过反射调用方法 30 Class clazz = cc.toClass(); 31 Object obj = clazz.newInstance();//通过调用无参构造器,生成新的对象 32 Method m = clazz.getDeclaredMethod("add", int.class, int.class); 33 Object result = m.invoke(obj, 2, 3); 34 System.out.println(result); 35 } 36 37 //修改已有的方法 38 public static void test03() throws Exception{ 39 ClassPool pool = ClassPool.getDefault(); 40 CtClass cc = pool.get("com.code.javassistdemo.example.Person"); 41 42 CtMethod cm = cc.getDeclaredMethod("hello",new CtClass[]{pool.get("java.lang.String")}); 43 cm.insertBefore("System.out.println(\"调用前\");");//调用前 44 cm.insertAt(31, "System.out.println(\"31\");");//行号 45 cm.insertAfter("System.out.println(\"调用后\");");//调用后 46 47 //通过反射调用方法 48 Class clazz = cc.toClass(); 49 Object obj = clazz.newInstance(); 50 Method m = clazz.getDeclaredMethod("hello", String.class); 51 Object result = m.invoke(obj, "张三"); 52 System.out.println(result); 53 } 54 55 //修改已有属性 56 public static void test04() throws Exception{ 57 ClassPool pool = ClassPool.getDefault(); 58 CtClass cc = pool.get("com.code.javassistdemo.example.Person"); 59 60 //属性 61 CtField cf = new CtField(CtClass.intType,"age",cc); 62 cf.setModifiers(Modifier.PRIVATE); 63 cc.addField(cf); 64 //增加响应的get set方法 65 cc.addMethod(CtNewMethod.getter("getAge",cf)); 66 cc.addMethod(CtNewMethod.setter("setAge",cf)); 67 68 //访问属性 69 Class clazz = cc.toClass(); 70 Object obj = clazz.newInstance(); 71 Field field = clazz.getDeclaredField("age"); 72 System.out.println(field); 73 Method m = clazz.getDeclaredMethod("setAge", int.class); 74 m.invoke(obj, 16); 75 Method m2 = clazz.getDeclaredMethod("getAge", null); 76 Object resutl = m2.invoke(obj,null); 77 System.out.println(resutl); 78 } 79 80 //操作构造方法 81 public static void test05() throws Exception{ 82 ClassPool pool = ClassPool.getDefault(); 83 CtClass cc = pool.get("com.code.javassistdemo.example.Person"); 84 85 CtConstructor[] cons = cc.getConstructors(); 86 for(CtConstructor con:cons){ 87 System.out.println(con); 88 } 89 } 90 public static void main(String[] args) throws Exception { 91 test01(); 92 // test02(); 93 // test03(); 94 // test04(); 95 // test05(); 96 } 97 }