Java 编程的动态性,第 6 部分: 利用 Javassist 进行面向方面的更改
2010-03-18 00:00:00 来源:WEB开发网通过在 VerboseEditor 中实现适当的方法,可以容易地增加对报告强制类型转换、 instanceof 检查和 catch 块的支持。但是只列出有关这些组件项的信息有些乏味,所以让我们来实际修改项目吧。
进行剖析
清单 4对类的剖析列出了基本组件操作。容易看出在实现面向方面的功能时使用这些操作会多么有用。例如,报告对所选字段的所有写访问的记录器(logger)在许多应用程序中都会发挥作用。无论如何,我已经承诺要为您介绍如何完成 这类工作。
幸运的是,就本文讨论的主题来说, ExprEditor 不但让我知道代码中有什么操作,它还让我可以修改所报告的操作。在不同的 ExprEditor.edit() 方法调用中传递的参数类型分别定义一种 replace() 方法。如果向这个方法传递一个普通 Javassist 源代码格式的语句(在 第 4 部分中介绍),那么这个语句将编译为字节码,并且用来替换原来的操作。这使对字节码的切片和切块变得容易。
清单 5 显示了一个代码替换的应用程序。在这里我不是记录操作,而是选择实际修改存储在所选字段中的 String 值。在 FieldSetEditor 中,我实现了匹配字段访问的方法签名。在这个方法中,我只检查两样东西:字段名是否是我所查找的,操作是否是一个存储过程。找到匹配后,就用使用实际的 TranslateEditor 应用程序类中 reverse() 方法调用的结果来替换原来的存储。 reverse() 方法就是将原来字符串中的字母顺序颠倒并输出一条消息表明它已经使用过了。
清单 5. 颠倒字符串集
public class TranslateEditor
{
public static void main(String[] args) {
if (args.length >= 3) {
try {
// set up class loader with translator
EditorTranslator xlat =
new EditorTranslator(args[0], new FieldSetEditor(args[1]));
ClassPool pool = ClassPool.getDefault(xlat);
Loader loader = new Loader(pool);
// invoke the "main" method of the application class
String[] pargs = new String[args.length-3];
System.arraycopy(args, 3, pargs, 0, pargs.length);
loader.run(args[2], pargs);
} catch (Throwable ex) {
ex.printStackTrace();
}
} else {
System.out.println("Usage: TranslateEditor clas-name " +
"field-name main-class args...");
}
}
public static String reverse(String value) {
int length = value.length();
StringBuffer buff = new StringBuffer(length);
for (int i = length-1; i >= 0; i--) {
buff.append(value.charAt(i));
}
System.out.println("TranslateEditor.reverse returning " + buff);
return buff.toString();
}
public static class EditorTranslator implements Translator
{
private String m_className;
private ExprEditor m_editor;
private EditorTranslator(String cname, ExprEditor editor) {
m_className = cname;
m_editor = editor;
}
public void start(ClassPool pool) {}
public void onWrite(ClassPool pool, String cname)
throws NotFoundException, CannotCompileException {
if (cname.equals(m_className)) {
CtClass clas = pool.get(cname);
clas.instrument(m_editor);
}
}
}
public static class FieldSetEditor extends ExprEditor
{
private String m_fieldName;
private FieldSetEditor(String fname) {
m_fieldName = fname;
}
public void edit(FieldAccess arg) throws CannotCompileException {
if (arg.getFieldName().equals(m_fieldName) && arg.isWriter()) {
StringBuffer code = new StringBuffer();
code.append("$0.");
code.append(arg.getFieldName());
code.append("=TranslateEditor.reverse($1);");
arg.replace(code.toString());
}
}
}
}
更多精彩
赞助商链接