但用于日志记录的代码和主要用于其它职责的代码缠绕在一起。根据所解决的问题的复杂程度和作用域的不同,所引起的混乱可大可小。更改一个应用程序的日志记录策略可能涉及数百次编辑 ― 即使可行,这是个令人头疼的任务。
考虑一下以下代码:
清单 1. 日志调用手工插入到每个方法中
|
使用aop后,更改的代码为:
清单 2. 自动应用于每个方法的记录日志调用
|
要理解 Pointcut,必需知道 join point 是什么。join point 表示在程序执行中明确定义的点。AspectJ 中典型的 join point 包括方法调用、对类成员的访问以及异常处理程序块的执行。join point 可以包含其它 join point。例如,一个方法调用可能在它返回之前引起其它方法调用。那么,Pointcut 就是一种语言构造,这种构造根据已定义的标准挑选一组 join point。示例中的第一个 Pointcut 称为 publicMethods
,选择 org.apache.cactus
包中的所有公用(public)方法的执行。 execution
是一个原始的 Pointcut(就象 int
是一种原始的 Java 类型)。它选择与其括号中定义的方法说明匹配的任何方法的执行。方法说明允许包含通配符;示例中的一个方法说明包含了几个通配符。第二个名为 logObjectCalls
的 Pointcut 选择了 Logger
类中的所有方法的执行。第三个 Pointcut loggableCalls
,通过使用 && !
合并了前两个 Pointcut,这意味着它选择了除 Logger
类中的公用方法以外, org.apache.cactus
中所有的公用方法。(记录 log 方法将导致无限递归。)
既然 Aspect 已经定义了它应该记录的点,它使用 Advice 来完成实际的日志记录。Advice 是在 join point 之前、之后或周围执行的代码。相对于 Pointcut 来定义 Advice,说类似于“在想要记录的每个方法调用之后运行这些代码”这样的话。因此 Advice 如下:
|
Advice 使用 Logger
类,其入口和出口方法类似于下列代码:
|
在示例中,传递到记录器的 String
是从 thisJoinPoint
派生的,这是一个特殊的反射对象,它允许访问 join point 执行所处的运行时上下文。在 Cactus 实际使用的 Aspect 中,Advice 使用这种对象来检索传递到每个记录的方法调用中的方法参数。当日志记录 Aspect 应用于代码时,方法调用的结果如下:
|