AspectJ 中的 Joinpoint 与 ProceedingJoinPoint
1. 简介
在这个简短的教程中,我们将了解*AspectJ 中JoinPoint和ProceedingJoinPoint*接口之间的区别。
我们将通过简短的解释和代码示例对其进行介绍。
2. JoinPoint
JoinPoint是一个AspectJ接口,它提供对给定连接点可用状态的反射访问,例如方法参数、返回值或抛出的异常。它还提供有关方法本身的所有静态信息。
我们可以将它与*@Before*、@After、@AfterThrowing和*@AfterReturning*建议一起使用。这些切入点将分别在方法执行前、执行后、返回值后、或仅在抛出异常后、或仅在方法返回值后启动。
为了更好地理解,让我们看一个基本的例子。首先,我们需要声明一个切入点。我们将定义为ArticleService类中*getArticleList()*的每次执行:
@Pointcut("execution(* com.blogdemo.ArticleService.getArticleList(..))")
public void articleListPointcut(){ }
接下来,我们可以定义通知。在我们的示例中,我们将使用*@Before*:
@Before("articleListPointcut()")
public void beforeAdvice(JoinPoint joinPoint) {
log.info(
"Method {} executed with {} arguments",
joinPoint.getStaticPart().getSignature(),
joinPoint.getArgs()
);
}
在上面的示例中,我们使用*@Before*建议来记录方法执行及其参数。一个类似的用例是记录我们代码中发生的异常:
@AfterThrowing(
pointcut = "articleListPointcut()",
throwing = "e"
)
public void logExceptions(JoinPoint jp, Exception e) {
log.error(e.getMessage(), e);
}
通过使用*@AfterThrowing*建议,我们确保仅在发生异常时才进行日志记录。
3. ProceedingJoinPoint
ProceedingJoinPoint是JoinPoint的扩展,它公开了附加的*proceed()*方法。调用时,代码执行会跳转到下一个通知或目标方法。它使我们能够控制代码流并决定是否继续进行进一步的调用。
可以只使用*@Around*建议,它围绕整个方法调用:
@Around("articleListPointcut()")
public Object aroundAdvice(ProceedingJoinPoint pjp) {
Object articles = cache.get(pjp.getArgs());
if (articles == null) {
articles = pjp.proceed(pjp.getArgs());
}
return articles;
}
在上面的示例中,我们说明了*@Around*建议最流行的用法之一。只有当缓存没有返回结果时,才会调用实际的方法。这正是Spring Cache Annotations 的工作方式。
我们还可以使用 ProceedingJoinPoint和 @Around通知来重试操作以防出现任何异常:
@Around("articleListPointcut()")
public Object aroundAdvice(ProceedingJoinPoint pjp) {
try {
return pjp.proceed(pjp.getArgs());
} catch (Throwable) {
log.error(e.getMessage(), e);
log.info("Retrying operation");
return pjp.proceed(pjp.getArgs());
}
}
例如,此解决方案可用于在网络中断的情况下重试 HTTP 调用。