Javassist

2.    ClassPool

ClassPool对象是一个CtClass对象的容器。一个CtClass对象被构建后,它被记录在ClassPool中。这是因为当编译的原文件关联到CtClass表示的类, 编译器要访问CtClass对象。

 

   例如,假定一个新方法getter()要加入到CtClass对象表示的的Point类。程序试图编译Point中的方法getter()的源代码,用编译过的代码做为方法内容,将它加到另一个类Line中。如果CtClass对象表示的Point丢失了,编译器将不能编译getter()方法。注册初始的类不包含getter()方法。因此,为了正确的编译一个方法,ClassPool必须拥有程序运行时所有的CtClass实例。

 

避免内存溢出

ClassPool的特点决定了当 CtClass对象数量很多时,它所占的内存会非常大。为了避免这种情况发生,你可以明确的移除一个ClassPool中的不需要的CtClass对象。如果用CtClass的detach()方法,CtClass对象将从ClassPool中移除。例如:


CtClass cc = ... ;


cc.writeFile();


cc.detach();


执行deatach()后,将不能执行CtClass对象的任何方法。但是,可以执行ClassPool的get()方法得到表示同一个类的CtClass实例。执行get()后,ClassPool再次读取类文件,重新建立CtClass对象。

 

  另一个办法是用新的ClassPool替换老的。如果老的 ClassPool当做垃圾被回收了,它里面的CtClass对象也会被回收,建立新的ClassPool实例,执行下面的代码片段:


  

ClassPool cp = new ClassPool(true);
 
        // if needed, append an extra search path by appendClassPath()


  通过ClassPool.getDefault()构建默认行为的ClassPool对象。注意ClassPool.getDefault()是为了方便提供的单子工厂方法。它保持着单独的对象并重用它。getDefault()返回的ClassPool对象没有特别的作用。getDefault()是一个方便的方法。

 注意new ClassPool(true)是个方便的构造器,它构建一个ClassPool对象并加入系统搜索路径。执行它等同于下面的代码:


ClassPool cp = new ClassPool();
 
cp.appendSystemPath();  // or append another path by appendClassPath()



级联的ClassPools

如果程序运行在web服务器中,可能需要建立多个ClassPool;要为每个类载入器建一个ClassPool。程序将不用getDefault(),用ClassPool构造器建一个ClassPool对象。

多个CLassPool对象像java.lang.ClassLoader一样级联起来。例如,


   

ClassPool parent = ClassPool.getDefault();
 
        ClassPool child = new ClassPool(parent);
 
        child.insertClassPath("./classes");

如果执行child.get(),孩子ClassPool首先去查找父ClassPool。如果说父查找失败,孩子再去./classes目录下查找类。

如果child.childFirstLookup为true,先在孩子中查找,再到父中查。例如:


ClassPool parent = ClassPool.getDefault();
 
ClassPool child = new ClassPool(parent);
 
child.appendSystemPath();// the same class path as the default one.
 
child.childFirstLookup = true;    // changes the behavior of the child.