Java 1.5中面向方面(AOP)编程[组图](7)
取样(Sampling)
我现在有办法把StackTraceElement数组转换为@Status注解堆栈。这种操作比表明看到的更加有用。Java 1.5中的另一个新特性--线程反省(introspection)--使我们能够从当前正在运行的线程中得到准确的StackTraceElement数组。有了这两部分信息之后,我们就可以构造JstatusBar的另一种实现。StatusManager将不会在发生方法调用的时候接收通知,而是简单地启动一个附加的线程,让它负责在正常的间隔期间抓取堆栈跟踪信息和每个步骤的状态。只要这个间隔期间足够短,用户就不会感觉到更新的延迟。
下面使"sampler"线程背后的代码,它跟踪另一个线程的经过:
class StatusSampler implements Runnable
{
private Thread watchThread;
public StatusSampler (Thread watchThread)
{
this.watchThread = watchThread;
}
public void run ()
{
while (watchThread.isAlive()) {
// 从线程中得到堆栈跟踪信息
StackTraceElement[] stackTrace =watchThread.getStackTrace();
// 从堆栈跟踪信息中提取状态消息
List<Status> statusList =StatusFinder.getStatus(stackTrace);
Collections.reverse(statusList);
// 用状态消息建立某种状态
StatusState state = new StatusState();
for (Status s : statusList) {
String message = s.value();
state.push(message);
}
// 更新当前的状态
StatusManager.setState(watchThread,state);
//休眠到下一个周期
try {
Thread .sleep(SAMPLING_DELAY);
} catch (InterruptedException ex) {}
}
//状态复位
StatusManager.setState(watchThread,new StatusState());
}
}
与增加方法调用、手动或通过重构相比,取样对程序的侵害性(invasive)更小。我根本不需要改变建立过程或命令行参数,或修改启动过程。它也允许我通过调整SAMPLING_DELAY来控制占用的开销。不幸的是,当方法调用开始或结束的时候,这种方法没有明确的回调。除了状态更新的延迟之外,没有原因要求这段代码在那个时候接收回调。但是,未来我能够增加一些额外的代码来跟踪每个方法的准确的运行时。通过检查StackTraceElement是可以精确地实现这样的操作的。
通过线程取样实现JStatusBar的代码可以在peekinginside-pt2.tar.gz文件的/code/05_sampling目录中找到。
在执行过程中重构字节码
通过把取样的方法与重构组合在一起,我能够形成一种最终的实现,它提供了各种方法的最佳特性。默认情况下可以使用取样,但是应用程序的花费时间最多的方法可以被个别地进行重构。这种实现根本不会安装ClassTransformer,但是作为代替,它会一次一个地重构方法以响应取样过程中收集到的数据。
为了实现这种功能,我将建立一个新类InstrumentationManager,它可以用于重构和不重构独立的方法。它可以使用新的Instrumentation.redefineClasses方法来修改空闲的类,同时代码则可以不间断执行。前面部分中增加的StatusSampler线程现在有了额外的职责,它把任何自己"发现"的@Status方法添加到集合中。它将周期性地找出最坏的冒犯者并把它们提供给InstrumentationManager以供重构。这允许应用程序更加精确地跟踪每个方法的启动和终止时刻。
- 上一篇:Java串行端口技术协议[组图]
- 下一篇:Java堆的管理--垃圾回收