Java 编程的动态性,第 6 部分: 利用 Javassist 进行面向方面的更改
2010-03-18 00:00:00 来源:WEB开发网清单 1 给出了使用方法调用转换的一个例子。在这个例子中,转换只是增加了一个方法正在被调用的通知。在代码中,首先得到将要使用的 javassist.ClassPool 实例,将它配置为与一个翻译器一同工作 (正如在前面 第 5 部分 所看到的)。然后,通过 ClassPool 访问两个方法定义。第一个方法定义针对的是要监视的“set”类型的方法(类和方法名来自命令行参数),第二个方法定义针对的是 reportSet() 方法 ,它位于TranslateConvert 类中,并会报告对第一个方法的调用。
有了方法信息后,就可以用 CodeConverterinsertBeforeMethod() 配置一个转换,以在每次调用这个 set 方法之前增加一个对报告方法的调用。然后所要做的就是将这个转换器应用到一个或者多个类上。在清单 1 的代码中,我是通过调用类对象的 instrument() 方法,在 ConverterTranslator 内部类的 onWrite() 方法中完成这项工作的。这将自动对从 ClassPool 实例中加载的每一个类应用这个转换。
清单 1. 使用 CodeConverter
public class TranslateConvert
{
public static void main(String[] args) {
if (args.length >= 3) {
try {
// set up class loader with translator
ConverterTranslator xlat =
new ConverterTranslator();
ClassPool pool = ClassPool.getDefault(xlat);
CodeConverter convert = new CodeConverter();
CtMethod smeth = pool.get(args[0]).
getDeclaredMethod(args[1]);
CtMethod pmeth = pool.get("TranslateConvert").
getDeclaredMethod("reportSet");
convert.insertBeforeMethod(smeth, pmeth);
xlat.setConverter(convert);
Loader loader = new Loader(pool);
// invoke "main" method of application class
String[] pargs = new String[args.length-3];
System.arraycopy(args, 3, pargs, 0, pargs.length);
loader.run(args[2], pargs);
} catch ...
}
} else {
System.out.println("Usage: TranslateConvert " +
"clas-name set-name main-class args...");
}
}
public static void reportSet(Bean target, String value) {
System.out.println("Call to set value " + value);
}
public static class ConverterTranslator implements Translator
{
private CodeConverter m_converter;
private void setConverter(CodeConverter convert) {
m_converter = convert;
}
public void start(ClassPool pool) {}
public void onWrite(ClassPool pool, String cname)
throws NotFoundException, CannotCompileException {
CtClass clas = pool.get(cname);
clas.instrument(m_converter);
}
}
}
更多精彩
赞助商链接