22

当试图实现一个负责捕获和记录某种类型的错误的方面时,我最初认为这可以使用 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());
  }
}

请注意,在此示例中,我捕获了所有异常,因为它只是一个示例。我知道吞下所有异常是不好的做法,但是对于我当前的用例,我希望只记录一种特殊类型的异常,同时避免重复的日志记录逻辑。

4

2 回答 2

24

Spring参考文档说:

“当匹配的方法执行通过抛出异常退出时,抛出建议运行后”

到那时,捕获异常为时已晚,因为它已经被抛出并且方法已经退出。您对@Around 建议采取的方法是在方法退出之前实际捕获异常并处理它的唯一方法。

于 2010-03-24T06:59:10.093 回答
3

实际上,也可以在 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 包)

于 2020-02-02T17:40:47.393 回答