1. 概述
在本教程中,我们将在调用已配置类的方法时使用AspectJ编写跟踪日志记录输出。通过使用 AOP 建议来编写跟踪日志记录输出,我们将逻辑封装到单个编译单元中。
我们的示例扩展了AspectJ 简介中提供的信息。
2. 跟踪记录注释
我们将使用注释来配置类,以便可以跟踪它们的方法调用。 使用注释为我们提供了一种简单的机制,可以将跟踪日志记录输出添加到新代码中,而无需直接添加日志记录语句。
让我们创建注释:
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface Trace {
}
3. 创建我们的方面
我们将创建一个方面来定义 切入点 ,以匹配我们关心的连接点和包含要执行的逻辑的 周围 建议。
我们的方面将类似于:
public aspect TracingAspect {
private static final Log LOG = LogFactory.getLog(TracingAspect.class);
pointcut traceAnnotatedClasses(): within(@Trace *) && execution(* *(..));
Object around() : traceAnnotatedClasses() {
String signature = thisJoinPoint.getSignature().toShortString();
LOG.trace("Entering " + signature);
try {
return proceed();
} finally {
LOG.trace("Exiting " + signature);
}
}
}
在我们的方面,我们定义了一个名为 traceAnnotatedClasses 的 切入点 ,以匹配使用 Trace 注释注释的类 中 方法的 执行 。 通过定义和命名 切入点, 我们可以像重用类中的方法一样重用它。 我们将使用这个命名 切入点 来 围绕 建议配置我们的切入点。
我们的 周围 建议将代替与我们的 切入点 匹配的任何连接点执行,并将返回一个 Object 。 通过具有 Object 返回类型,我们可以考虑具有任何返回类型的建议方法,甚至是 void 。
我们检索匹配连接点的签名,以创建签名的短 字符串 表示形式,以将上下文添加到我们的跟踪消息中。因此,我们的日志输出将包含类的名称和执行的方法,这为我们提供了一些所需的上下文。
在跟踪输出调用之间,我们调用了一个名为 proceed 的方法。 此方法可用于 周围 通知,以便继续执行匹配的连接点。 返回类型将是 Object ,因为我们无法在编译时知道返回类型。在将最终跟踪输出发送到日志后,我们将将此值发送回调用者。
我们将 proceed() 调用包装在 try / finally 块中,以确保写入退出消息。 如果我们想跟踪抛出的异常,我们可以添加 after() 建议,以便在抛出异常时写入日志消息:
after() throwing (Exception e) : traceAnnotatedClasses() {
LOG.trace("Exception thrown from " + thisJoinPoint.getSignature().toShortString(), e);
}
4. 注释我们的代码
现在我们需要启用我们的跟踪。让我们创建一个简单的类并使用自定义注释激活跟踪日志记录:
@Trace
@Component
public class MyTracedService {
public void performSomeLogic() {
...
}
public void performSomeAdditionalLogic() {
...
}
}
使用 Trace 注释后,我们类中的方法将与我们定义的 切入点 相匹配。当这些方法执行时,跟踪消息将被写入日志。
运行调用这些方法的代码后,我们的日志输出应包含类似于以下内容的内容:
22:37:58.867 [main] TRACE c.b.a.c.TracingAspect - Entering MyTracedService.performSomeAdditionalLogic()
22:37:58.868 [main] INFO c.b.a.c.MyTracedService - Inside performSomeAdditionalLogic...
22:37:58.868 [main] TRACE c.b.a.c.TracingAspect - Exiting MyTracedService.performSomeAdditionalLogic()
22:37:58.869 [main] TRACE c.b.a.c.TracingAspect - Entering MyTracedService.performSomeLogic()
22:37:58.869 [main] INFO c.b.a.c.MyTracedService - Inside performSomeLogic...
22:37:58.869 [main] TRACE c.b.a.c.TracingAspect - Exiting MyTracedService.performSomeLogic()
5. 结论
在本文中,我们使用 AspectJ 通过类上的单个注释来拦截类的所有方法。这样做使我们能够快速将跟踪日志记录功能添加到新代码中。
我们还将跟踪日志记录输出逻辑合并到单个编译单元,以提高随着应用程序的发展修改跟踪日志记录输出的能力。
与往常一样,本文的完整源代码可以在 GitHub 上获取。