Java 编程的动态性, 第四部分: 用 Javassist 进行类转换
2010-03-18 00:00:00 来源:WEB开发网通过 Javassist 可以很好地利用这种使用拦截器方法的方法。因为整个方法是一个块,所以我可以毫无问题地在正文中定义并且使用局部变量。为拦截器方法生成源代码也很容易 -- 对于任何可能的方法,只需要几个替换。
运行拦截
实现添加方法计时的代码要用到在 Javassist 基础中描述的一些 Javassist API。清单 4 展示了该代码,它是一个带有两个命令行参数的应用程序,这两个参数分别给出类名和要计时的方法名。 main() 方法的正文只给出类信息,然后将它传递给 addTiming() 方法以处理实际的修改。 addTiming() 方法首先通过在名字后面附加“ $impl” 重命名现有的方法,接着用原来的方法名创建该方法的一个拷贝。然后它用含有对经过重命名的原方法的调用的计时代码替换拷贝方法的正文。
清单4. 用 Javassist 添加拦截器方法
public class JassistTiming
{
public static void main(String[] argv) {
if (argv.length == 2) {
try {
// start by getting the class file and method
CtClass clas = ClassPool.getDefault().get(argv[0]);
if (clas == null) {
System.err.println("Class " + argv[0] + " not found");
} else {
// add timing interceptor to the class
addTiming(clas, argv[1]);
clas.writeFile();
System.out.println("Added timing to method " +
argv[0] + "." + argv[1]);
}
} catch (CannotCompileException ex) {
ex.printStackTrace();
} catch (NotFoundException ex) {
ex.printStackTrace();
} catch (IOException ex) {
ex.printStackTrace();
}
} else {
System.out.println("Usage: JassistTiming class method-name");
}
}
private static void addTiming(CtClass clas, String mname)
throws NotFoundException, CannotCompileException {
// get the method information (throws exception if method with
// given name is not declared directly by this class, returns
// arbitrary choice if more than one with the given name)
CtMethod mold = clas.getDeclaredMethod(mname);
// rename old method to synthetic name, then duplicate the
// method with original name for use as interceptor
String nname = mname+"$impl";
mold.setName(nname);
CtMethod mnew = CtNewMethod.copy(mold, mname, clas, null);
// start the body text generation by saving the start time
// to a local variable, then call the timed method; the
// actual code generated needs to depend on whether the
// timed method returns a value
String type = mold.getReturnType().getName();
StringBuffer body = new StringBuffer();
body.append("{\nlong start = System.currentTimeMillis();\n");
if (!"void".equals(type)) {
body.append(type + " result = ");
}
body.append(nname + "($$);\n");
// finish body text generation with call to print the timing
// information, and return saved value (if not void)
body.append("System.out.println(\"Call to method " + mname +
" took \" +\n (System.currentTimeMillis()-start) + " +
"\" ms.\");\n");
if (!"void".equals(type)) {
body.append("return result;\n");
}
body.append("}");
// replace the body of the interceptor method with generated
// code block and add it to class
mnew.setBody(body.toString());
clas.addMethod(mnew);
// print the generated code block just to show what was done
System.out.println("Interceptor method body:");
System.out.println(body.toString());
}
}
更多精彩
赞助商链接