Java 1.5中面向方面(AOP)编程[组图](4)
下面是表现一个普通方法调用的字节码,它被StatusManager更新环绕着:
0: ldc #2; //字符串消息
2: invokestatic #3; //方法StatusManager.push:(LString;)V
5: invokestatic #4; //方法 doSomething:()V
8: invokestatic #5; //方法 StatusManager.pop:()V
11: return
下面是相同的方法调用,但是位于try-finally代码块中,因此,如果它产生了异常会调用StatusManager.pop():
0: ldc #2; //字符串消息
2: invokestatic #3; //方法 StatusManager.push:(LString;)V
5: invokestatic #4; //方法 doSomething:()V
8: invokestatic #5; //方法 StatusManager.pop:()V
11: goto 20
14: astore_0
15: invokestatic #5; //方法 StatusManager.pop:()V
18: aload_0
19: athrow
20: return
Exception table:
from to target type
5 8 14 any
14 15 14 any
你可以发现,为了实现一个try-finally,我必须复制一些指令,并添加了几个跳转和异常表记录。幸运的是,BCEL的InstructionList类使这种工作相当简单。
在运行时重构字节码
现在我拥有了一个基于注解修改类的接口和该接口的具体实现了,下一步是编写调用它的实际框架组件。实际上我将编写少量的框架组件,先从运行时重构所有类的框架组件开始。由于这种操作会在build过程中发生,我决定为它定义一个Ant事务。build.xml文件中的重构目标的声明应该如下:
<instrument class="com.pkg.OurInstrumentor">
<fileset dir="$(classes.dir)">
<include name="**/*.class"/>
</fileset>
</instrument>
为了实现这种事务,我必须定义一个实现org.apache.tools.ant.Task接口的类。我们的事务的属性和子元素(sub-elements)都是通过set和add方法调用传递进来的。我们调用执行(execute)方法来实现事务所要执行的工作--在示例中,就是重构<fileset>中指定的类文件。
public class InstrumentTask extends Task {
...
public void setClass (String className) { ... }
public void addFileSet (FileSet fileSet) { ... }
public void execute () throws BuildException {
Instrumentor inst = getInstrumentor();
try {
DirectoryScanner ds =fileSet.getDirectoryScanner(project);
// Java 1.5 的"for" 语法
for (String file : ds.getIncludedFiles()) {
instrumentFile(inst, file);
}
} catch (Exception ex) {
throw new BuildException(ex);
}
}
...
}
- 上一篇:Java串行端口技术协议[组图]
- 下一篇:Java堆的管理--垃圾回收