1、简介
javassist是一个开源的分析、编辑和创建java字节码的类库。不需要了解虚拟机指令,就能动态生成类或者改变类的结构。
2、下载
(1)下载链接http://www.csg.ci.i.u-tokyo.ac.jp/~chiba/javassist/
(2)使用的版本是javassist-3.18.0-GA。
Javassist是一个执行字节码操作的强而有力的驱动代码库。它允许开发者自由的在一个已经编译好的类中添加新的方法,或者是修改已有的方法。但是,和其他的类似库不同的是,Javassist并不要求开发者对字节码方面具有多么深入的了解,同样的,它也允许开发者忽略被修改的类本身的细节和结构。
字节码驱动通常被用来执行对于已经编译好的类的修改,或者由程序自动创建执行类等等等等相关方面的操作。这就要求字节码引擎具备无论是在运行时或是编译时都能修改程序的能力。当下有些技术便是使用字节码来强化已经存在的Java类的,也有的则是使用它来使用或者产生一些由系统在运行时动态创建的类。举例而言,JDO1.0规范就使用了字节码技术对数据库中的表进行处理和预编译,并进而包装成Java类。特别是在面向对象驱动的系统开发中,相当多的框架体系使用字节码以使我们更好的获得程序的范型性和动态性。而某些EJB容器,比如JBOSS项目,则通过在运行中动态的创建和加载EJB,从而戏剧性的缩短了部署EJB的周期。这项技术是如此的引人入胜,以至于在JDK中也有了标准的java.lang.reflect.Proxy类来执行相关的操作。
但是,尽管如此,编写字节码对于框架程序开发者们而言,却是一个相当不受欢迎的繁重任务。学习和使用字节码在某种程度上就如同使用汇编语言。这使得于大多数开发者而言,尽管在程序上可以获得相当多的好处,可攀登它所需要的难度则足以冷却这份热情。不仅如此,在程序中使用字节码操作也大大的降低了程序的可读性和可维护性。
这是一块很好的奶油面包,但是我们却只能隔着橱窗流口水…难道我们只能如此了吗?
所幸的是,我们还有Javassist。Javassist是一个可以执行字节码操作的函数库,可是尽管如此,它却是简单而便与理解的。他允许开发者对自己的程序自由的执行字节码层的操作,当然了,你并不需要对字节码有多深的了解,或者,你根本就不需要了解。
二、具体使用
Javassist的最外层的API和JAVA的反射包中的API颇为类似。它使你可以在装入ClassLoder之前,方便的查看类的结构。它主要由CtClass,,CtMethod,,以及CtField几个类组成。用以执行和JDK反射API中java.lang.Class,,java.lang.reflect.Method,, java.lang.reflect.Method .Field相同的操作。这些类可以使你在目标类被加载前,轻松的获得它的结构,函数,以及属性。此外,不仅仅是在功能上,甚至在结构上,这些类的执行函数也和反射的API大体相同。比如getName,getSuperclass,getMethods,,getSignature,等等。如果你对JAVA的反射机制有所了解的话,使用Javassist的这一层将会是轻松而快乐的。
接下来我们将给出一个使用Javassist来读取org.geometry.Point.class的相关信息的例子(当然了,千万不要忘记引入javassist.*包):
ClassPool pool = ClassPool.getDefault();CtClass pt = pool.get("org.geometry.Point");System.out.println(pt.getSuperclass().getName());
其中,ClassPool是CtClass 的创建工厂。它在class path中查找CtClass的位置,并为每一个分析请求创建一个CtClass实例。而“getSuperclass().getName()”则展示出org.geometry.Point.class所继承的父类的名字。
但是,和反射的API不尽相同的是,Javassist并不提供构造的能力,换句话说,我们并不能就此得到一个org.geometry.Point.class类的实例。另一方面,在该类没有实例化前,Javassist也不提供对目标类的函数的调用接口和获取属性的值的方法。在分析阶段,它仅仅提供对目标类的类定义修改,而这点,却是反射API所无法做到的。
1、目标类和其父类之间的关系
例1:
pt.setSuperclass(pool.get("Figure"));
这样做将修改目标类和其父类之间的关系。我们将使org.geometry.Point.clas改继承自Figure类。当然了,就一致性而言,必须确保Figure类和原始的父类之间的兼容性。
2、往目标类中新增一个新的方法
而往目标类中新增一个新的方法则更加的简单了。首先我们来看字节码是如何形成的:
CtMethod m = CtNewMethod.make("public int xmove(int dx) { x += dx; }", pt);pt.addMethod(m);
CtMethod类的让我们要新增一个方法只需要写一段小小的函数。这可是一个天大的好消息,开发者们再也不用为了实现这么一个小小的操作而写一大段的虚拟机指令序列了。Javassist将使用一个它自带的编译器来帮我们完成这一切。
最后,千万别忘了指示Javassist把已经写好的字节码存入到你的目标类里:
pt.writeFile();
writeFile方法可以帮我们把修改好了的定义写到目标类的.class文件里。当然了,我们甚