1. 引言
在这个简短教程中,我们将探讨AspectJ接口JoinPoint
和ProceedingJoinPoint
之间的区别。我们将通过简洁的解释和代码示例来进行讲解。
2. JoinPoint
JoinPoint
是AspectJ
接口,它提供了对给定连接点(join point)状态的反射访问,如方法参数、返回值或抛出的异常。它还提供了关于方法的所有静态信息。
我们可以在@Before
、@After
、@AfterThrowing
和@AfterReturning
建议中使用它。这些切点分别会在方法执行前、执行后、返回值后或仅在抛出异常后、或仅在方法返回值后触发。
为了更好地理解,让我们看一个基本例子。首先,我们需要声明一个切点。我们将定义为ArticleService
类中的getArticleList()
方法的所有执行:
@Pointcut("execution(* com.baeldung.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缓存注解的工作方式。
我们还可以使用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调用。
4. 总结
在这篇文章中,我们了解了JoinPoint
和ProceedingJoinPoint
在AspectJ
中的区别。如往常一样,所有源代码可在GitHub上找到。