javassist的基本功能
Javassist是一個動態類庫,可以用來檢查、”動態”修改以及創建 Java類。其功能與jdk自帶的反射功能類似,但比反射功能更強大。
重要的類
ClassPool:javassist的類池,使用ClassPool 類可以跟蹤和控制所操作的類,它的工作方式與 JVM 類裝載器非常相似,
CtClass: CtClass提供了檢查類數據(如字段和方法)以及在類中添加新字段、方法和構造函數、以及改變類、父類和接口的方法。不過,Javassist 並未提供刪除類中字段、方法或者構造函數的任何方法。
CtField:用來訪問域
CtMethod :用來訪問方法
CtConstructor:用來訪問構造器
語法
使用javassist來編寫的代碼與java代碼不完全一致,主要的區別在於 javassist提供了一些特殊的標記符(以
示例
可以通過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