Javassist 是一个Java字节码操作类库,Java字节码被保存在一个称为class文件的二进制文件中,每个类文件都包含一个Java类或接口。
对于动态生成二进制字节码 class 有许多开源项目提供支持,CGLib、ASM、Javassis。他们都能够动态创建新类或新接口的二进制字节码,动态扩展现有类或接口的二进制字节码。CGLib 底层基于 ASM 实现,是一个高效高性能的生成库;ASM 是一个轻量级类库,但需要涉及到 JVM 的操作和指令;javassist则完全基于 Java API,但是性能差一些
Javassist的官方网站如下:
http://www.csg.ci.i.u-tokyo.ac.jp/~chiba/javassist/
如下的链接是一个很好的Javassist代码示例:
http://yonglin4605.iteye.com/blog/1396494
如下的链接深入研究了Javassist中的一些语法,其中第8小节处对参数形式的总结很有作用:
http://zhxing.iteye.com/blog/1703305
如下的链接是IBM DW关于Javassist一个较为完整的教程:
http://www.ibm.com/developerworks/cn/java/j-dyn0916/
如下的代码是动态创建Java类二进制字节码并通过反射调用的示例,可供参考:
- import java.lang.reflect.InvocationTargetException;
- import java.lang.reflect.Method;
- import javassist.CannotCompileException;
- import javassist.ClassPool;
- import javassist.CtClass;
- import javassist.CtConstructor;
- import javassist.CtField;
- import javassist.CtNewMethod;
- import javassist.Modifier;
- import javassist.NotFoundException;
- import javassist.CtField.Initializer;
- public class JavassistGenerator {
- public static void main(String[] args) throws CannotCompileException, NotFoundException, InstantiationException, IllegalAccessException, ClassNotFoundException, SecurityException, NoSuchMethodException, IllegalArgumentException, InvocationTargetException {
- // 创建类
- ClassPool pool = ClassPool.getDefault();
- CtClass cls = pool.makeClass("cn.ibm.com.TestClass");
- // 添加私有成员name及其getter、setter方法
- CtField param = new CtField(pool.get("java.lang.String"), "name", cls);
- param.setModifiers(Modifier.PRIVATE);
- cls.addMethod(CtNewMethod.setter("setName", param));
- cls.addMethod(CtNewMethod.getter("getName", param));
- cls.addField(param, Initializer.constant(""));
- // 添加无参的构造体
- CtConstructor cons = new CtConstructor(new CtClass[] {}, cls);
- cons.setBody("{name = \"Brant\";}");
- cls.addConstructor(cons);
- // 添加有参的构造体
- cons = new CtConstructor(new CtClass[] {pool.get("java.lang.String")}, cls);
- cons.setBody("{$0.name = $1;}");
- cls.addConstructor(cons);
- // 打印创建类的类名
- System.out.println(cls.toClass());
- // 通过反射创建无参的实例,并调用getName方法
- Object o = Class.forName("cn.ibm.com.TestClass").newInstance();
- Method getter = o.getClass().getMethod("getName");
- System.out.println(getter.invoke(o));
- // 调用其setName方法
- Method setter = o.getClass().getMethod("setName", new Class[] {String.class});
- setter.invoke(o, "Adam");
- System.out.println(getter.invoke(o));
- // 通过反射创建有参的实例,并调用getName方法
- o = Class.forName("cn.ibm.com.TestClass").getConstructor(String.class).newInstance("Liu Jian");
- getter = o.getClass().getMethod("getName");
- System.out.println(getter.invoke(o));
- }
- }
最后需要特别注意的是:
1. Javassist不支持要创建或注入的类中存在泛型参数
2. Javassist对@类型的注解(Annotation)只支持查询,不支持添加或修改