视中特别重要的领域。常见的问题包括编写得有毛病的查询、遗漏了索 引以及每个操作中过量的数据库请求。在这一节,我将对监视系统进行扩展,跟 踪数据库中与操作相关的活动。
开始时,我将监视数据库的连接次数和数据库语句的执行。为了有效地支持 这 个要求,我需要归纳性能监视信息,并允许跟踪嵌套在一个操作中的性能。我想 把性能的公共元素提取到一个抽象基类。每个基类负责跟踪某项操作前后的性能 ,还需要更新系统范围内这条信息的性能统计值。这样我就能跟踪嵌套的 servlet 请求,对于在 Web 应用程序中支持对控制器的跟踪,这也会很重要( 在 第二部分讨论)。
因为我想根据请求更新数据库的性能,所以我将采用 composite pattern 跟 踪由其他统计值持有的统计值。这样,操作(例如 servelt)的统计值就持有每 个数据库的性能统计。数据库的统计值持有有关连接次数的信息,并聚合每个单 独语句的额外统计值。图 4 显示整体设计是如何结合在一起的。清单 4 拥有新 的基监视方面,它支持对不同的请求进行监视。
图 4. 一般化后的监视设计
清单 4. 基监视方面
/** Base aspect for monitoring functionality.
* Uses the worker object pattern.
*/
public abstract aspect AbstractRequestMonitor {
/** Matches execution of the worker object
* for a monitored request.
*/
public pointcut
requestExecution(RequestContext requestContext) :
execution(* RequestContext.execute(..))
&& this(requestContext);
/** In the control flow of a monitored request,
* i.e., of the execution of a worker object.
*/
public pointcut inRequest(RequestContext requestContext) :
cflow(requestExecution(requestContext));
/** establish parent relationships
* for request context objects.
*/
// use of call is cleaner since constructors are called
// once but executed many times
after (RequestContext parentContext)
returning (RequestContext childContext) :
call(RequestContext+.new(..)) &&
inRequest(parentContext) {
childContext.setParent (parentContext);
}
public long getTime() {
return System.currentTimeMillis();
}
/** Worker object that holds context information
* for a monitored request.
*/
public abstract class RequestContext {
/** Containing request context, if any.
* Maintained by @link AbstractRequestMonitor
*/
protected RequestContext parent = null;
/** Associated performance statistics.
* Used to cache results of @link #lookupStats ()
*/
protected PerfStats stats;
/** Start time for monitored request. */
protected long startTime;
/**
* Record execution and elapsed time
* for each monitored request.
* Relies on @link #doExecute() to proceed
* with original request.
*/
public final Object execute() {
startTime = getTime();
Object result = doExecute ();
PerfStats stats = getStats();
if (stats != null) {
stats.recordExecution(startTime, getTime());
}
|