javassist入门

来源:互联网 发布:冒险岛市场实时数据 编辑:程序博客网 时间:2024/04/29 04:08

javassist的基本功能

Javassist是一个动态类库,可以用来检查、”动态”修改以及创建 Java类。其功能与jdk自带的反射功能类似,但比反射功能更强大。

重要的类

ClassPool:javassist的类池,使用ClassPool 类可以跟踪和控制所操作的类,它的工作方式与 JVM 类装载器非常相似,
CtClass: CtClass提供了检查类数据(如字段和方法)以及在类中添加新字段、方法和构造函数、以及改变类、父类和接口的方法。不过,Javassist 并未提供删除类中字段、方法或者构造函数的任何方法。
CtField:用来访问域
CtMethod :用来访问方法
CtConstructor:用来访问构造器

语法

使用javassist来编写的代码与java代码不完全一致,主要的区别在于 javassist提供了一些特殊的标记符(以System.out.println(Argument1:+1); 其中的$1表示第1个参数.

示例

可以通过javassist来修改java类的方法,来修改其实现。如下所示:

      ClassPool classPool = ClassPool.getDefault();      CtClass ctClass = classPool.get("org.light.lab.JavassistTest");      CtMethod ctMethod = ctClass.getDeclaredMethod("test");      ctMethod.setBody("System.out.println(\"this method is changed dynamically!\");");      ctClass.toClass();

上面的方法即是修改一个方法的实现,当调用ctClass.toClass()时,修改后的类将被当前的ClassLoader加载并实例化。

完整的代码:

public class ChangeDemo {

  public static void main(String[] args) throws NotFoundException, CannotCompileException {       replaceMethodBody("foo.Student", "execute", "System.out.println(\"this method is changed dynamically!\");");       Student student = new Student();       student.execute();   }public static void replaceMethodBody(String clazzName, String methodName, String newMethodBody) {    try {        CtClass clazz = ClassPool.getDefault().get(clazzName);        CtMethod method = clazz.getDeclaredMethod(methodName);        method.setBody(newMethodBody);        clazz.toClass();    } catch (NotFoundException | CannotCompileException e) {       throw new RuntimeException(e);    }}

}

限制与局限性

  • 需要注意的是,在调用ctClass.toClass()时,会加载此类,如果此类在之前已经被加载过,则会报一个duplicate load的错误,表示不能重复加载一个类。所以,修改方法的实现必须在修改的类加载之前进行。
  • 不能访问块之外的局部变量。如果在一个方法的开始和结尾都增加了代码段,那么在方法的结尾块中无法访问方法开始中的代码段中的变量(不太完美的解决方法是将原方法改名,然后再增加与原方法同名的方法)。

与aspectj的区别

使用aspectj也可以同样达到修改的效果,不过修改指定的类,则需要为修改这个类添加一个aspect,然后将这个aspect加入配置文件中以使其生效,比起javassist来说,修改一个类还是使用javassist相对简单一点。

容器中的Classpath

在tomcat之类的容器中是无法通过ClassPool.getDefault()获取到用户定义的类的,可以通过以下方法获取:
pool.insertClassPath(new ClassClassPath(this.getClass()));
或者:
ClassPool pool = ClassPool.getDefault();
pool.insertClassPath(“/usr/local/javalib”);

参考资料:

http://www.ibm.com/developerworks/cn/java/j-dyn0916/
http://jboss-javassist.github.io/javassist/tutorial/tutorial.html

1 0