当尝试实现一个负责捕获和记录某种类型错误的Aspect时,我最初认为可以使用AfterThrowing建议来实现。但是,他的建议似乎并没有捕获到异常,而只是提供了一个额外的切入点来对异常进行处理。
然后,唯一也会捕获相关异常的建议就是AroundAdvice-要么是我做错了。
任何人都可以断言,如果确实要捕获异常,则必须使用AroundAdvice?我使用的配置如下:
@Pointcut("execution(* test.simple.OtherService.print*(..))")
public void printOperation() {}
@AfterThrowing(pointcut="printOperation()", throwing="exception")
public void logException(Throwable exception) {
System.out.println(exception.getMessage());
}
@Around("printOperation()")
public void swallowException(ProceedingJoinPoint pjp) throws Throwable {
try {
pjp.proceed();
} catch (Throwable exception) {
System.out.println(exception.getMessage());
}
}
请注意,在此示例中,我捕获了所有异常,因为它只是一个示例。我知道吞下所有异常是一种不好的做法,但是对于我当前的用例,我希望只记录一种特殊类型的异常,同时避免重复的记录逻辑。
Spring reference文档说:
“引发建议后,匹配的方法执行退出引发异常”
到那时,因为已经抛出了异常并且该方法已经退出,现在赶上捕获异常的时机已经太迟了。 @Around建议所采用的方法是在方法退出之前实际捕获异常并对其进行处理的唯一方法。
实际上,也可以在AfterThrowing建议中捕获异常。我知道这是一个令人费解的示例,但它可以工作。
@Aspect
@Component
class MyAspect {
@Autowired
public Worker worker;
@Pointcut(value = "execution(public * com.ex*..*.*(..))")
public void matchingAll(){}
@AfterThrowing(pointcut = "matchingAll()", throwing = "e")
public void myAdvice(RuntimeException e){
Thread.setDefaultUncaughtExceptionHandler((t, e1) ->
System.out.println("Caught " + e1.getMessage()));
System.out.println("Worker returned " + worker.print());
}
}
@Component
class Worker {
public static int value = 0;
public int print() {
if (value++ == 0) {
System.out.println("Throwing exception");
throw new RuntimeException("Hello world");
} else {
return value;
}
}
}
@SpringBootApplication
@EnableAspectJAutoProxy
public class AdvicesDemo {
public static void main(String[] args) {
final ConfigurableApplicationContext applicationContext = SpringApplication.run(AdvicesDemo.class);
final Worker worker = applicationContext.getBean(Worker.class);
System.out.println("Worker returned " + worker.print());
System.out.println("All done");
}
}
您可以看到,它更多地是关于如何捕获最初引发的异常,从而防止其传播回调用方的。
GitHub的工作示例(检查com.example.advices包)