Spring AOP AfterThrowing 与 around Advice

发布于 2024-08-27 00:34:53 字数 809 浏览 7 评论 0原文

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

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

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.

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

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

@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.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

慈悲佛祖 2024-09-03 00:34:53

Spring 参考医生说:

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

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

The Spring reference doc says:

"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.

红ご颜醉 2024-09-03 00:34:53

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

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

@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)

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文