Java Spring AOP AfterThrowing vs.around Advice

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/2501955/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-13 08:32:24  来源:igfitidea点击:

Spring AOP AfterThrowing vs. Around Advice

javaspring-aop

提问by whiskerz

when trying to implement an Aspect, that is responsible for catching and logging a certain type of error, I initially thought this would be possible using the AfterThrowing advice. However it seems that his advice doesn't catch the exception, but just provides an additional entry point to do something with the exception.

当尝试实现一个负责捕获和记录某种类型错误的方面时,我最初认为这可以使用 AfterThrowing 建议。然而,他的建议似乎没有捕捉到异常,而只是提供了一个额外的入口点来处理异常。

The only advice which would also catch the exception in question would then be an AroundAdvice - either that or I did something wrong.

唯一可以捕获有问题的异常的建议就是AroundAdvice - 要么就是我做错了什么。

Can anyone assert that indeed if I want to catch the exception I have to use an AroundAdvice? The configuration I used follows:

谁能断言,如果我想捕获异常,我必须使用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());
  }
}

Note that in this example I caught all Exceptions, because it just is an example. I know its bad practice to just swallow all exceptions, but for my current use case I want one special type of exception to be just logged while avoiding duplicate logging logic.

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

采纳答案by Shane Bell

The Spring referencedoc says:

Spring参考医生说:

"After throwing advice runs when a matched method execution exits by throwing an exception"

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

By then it's too late to catch the exception as it has already been thrown and the method has exited. The approach you've taken with the @Around advice is the only way to actually catch the exception and deal with it before the method exits.

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

回答by fg78nc

Actually, it is possible to catch exception within AfterThrowing advice as well. I know it is a convoluted example, but it works.

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

As you can see it is more about how to catch originally thrown exception and thus prevent its propagation back to the caller.

正如您所看到的,它更多地是关于如何捕获最初抛出的异常,从而防止其传播回调用者。

Working example on GitHub(check com.example.advices package)

GitHub 上的工作示例(检查 com.example.advices 包)