【问题标题】:Spring AOP exception handler - execute only first aspect in orderingSpring AOP 异常处理程序 - 仅执行排序的第一个方面
【发布时间】:2020-12-16 13:20:12
【问题描述】:

UPD我已经更新了 Aspects 的代码以进一步抛出异常

我有 SpringBoot 应用程序、服务类,我需要为我的服务(不是 MVC)实现异常处理程序。任务是记录错误并将其进一步抛给客户端。

我决定将 Aspect 与 @AfterThrowing 建议一起使用。我将在AspectOne 方面捕获一些异常(扩展RuntimeException)。对于其他情况,我需要在 AspectTwo 方面捕获异常(扩展 RuntimeException)。

所以我做了以下代码:

public class MyOwnException extends RuntimeException {
}
@Aspect
@Order(0)
@Component
public class AspectOne {

@Pointcut("execution(* com.test.MyService.*(..))")
public void logException() {}

@AfterThrowing(pointcut="logException()", throwing="ex")
public void logException(MyOwnException ex) {
  System.out.println("MyOwnException has been thrown: " + ex.getMessage());
  throw ex;
}

}
@Aspect
@Order(1)
@Component
public class AspectTwo {

@Pointcut("execution(* com.test.MyService.*(..))")
public void logException() {}

@AfterThrowing(pointcut="logException()", throwing="ex")
public void logException(RuntimeException ex) {
  System.out.println("Some unknown exception has been thrown: " + ex);
  throw ex;
}

} 

问题是AspectTwoMyOwnExceptionRuntimeException 的其他祖先的两种情况下都被执行。如何限制AspectTwo 仅在AspectOne 未捕获异常时执行?

似乎@Order 注释不像我预期的那样工作。

【问题讨论】:

  • 订单完全符合预期。它首先执行 AspectOne,然后执行 AspectTwo。它不会限制执行,因为某些东西已经运行。在第二方面实现逻辑以忽略其他方面处理的错误。
  • 您的意思是在AspectTwo 中使用instanceof 来忽略它吗?我希望使用更通用的东西,比如说这个异常来自第一个方面”。否则每个新的异常我都应该添加到两个方面
  • 或者编写一个以某种方式处理众所周知的异常的单个方面,并且以不同的方式处理其他方式,您也不需要重新编写异常 AFAIK,它无论如何都会传播。

标签: spring exception aop exceptionhandler


【解决方案1】:

来个小技巧来表明异常已经被处理/建议如何?

还要注意,这里的执行顺序是AspectOneAspectTwo之前,Order应该指定为1表示AspectOne和0表示AspectTwo

来自参考文档部分:Advice Ordering

当多条建议都想在 相同的连接点? Spring AOP 遵循相同的优先级规则 AspectJ 来确定通知执行的顺序。最高的 优先建议首先“在途中”运行(因此,给定两个 在建议之前,优先级最高的先运行)。 “在 出路”从连接点开始,最高优先级的建议最后运行 (所以,给定两条事后建议,最高的一条 优先级将排在第二位)。

以下代码利用Throwable.addSuppressed() 方法指示异常对象已被处理/建议。

--

添加一个Exception 类用作指标。

public class AlreadyAdvicedIndicator extends Exception {

    private static final long serialVersionUID = 1L;
    
    public AlreadyAdvicedIndicator(String message) {
        super(message);
    }

}

AspectOne 修改后的Order 和添加抑制异常的逻辑。

@Component
@Aspect
@Order(1)
public class AspectOne {

    public static final String ALREADY_ADVICED_MSG="Adviced with AspectOne";
    
    private static final AlreadyAdvicedIndicator alreadyAdviced = new AlreadyAdvicedIndicator(ALREADY_ADVICED_MSG);

    @Pointcut("execution(* com.test.MyService.*(..))")
    public void logException() {}

    @AfterThrowing(pointcut="logException()", throwing="ex")
    public void logException(MyOwnException ex) {
      System.out.println("MyOwnException has been thrown: " + ex.getMessage());
      ex.addSuppressed(alreadyAdviced);
    }
}

AspectTwo 修改后的 Order 和检查已建议的逻辑。

@Component
@Aspect
@Order(0)
public class AspectTwo {

    @Pointcut("execution(* com.test.MyService.*(..))")
    public void logException() {
    }

    @AfterThrowing(pointcut = "logException()", throwing = "ex")
    public void logException(RuntimeException ex) {
        if (isAlreadyAdviced(ex)) {
            System.out.println("Already Adviced : Skipping");
        } else {
            System.out.println("RuntimeException has been thrown: " + ex.getMessage());
        }
    }

    private boolean isAlreadyAdviced(RuntimeException ex) {
        for(Throwable e : ex.getSuppressed()) {
            if(AspectOne.ALREADY_ADVICED_MSG.equals(e.getMessage())){
                return true;
            }
        }
        return false;
    }
}

【讨论】:

    猜你喜欢
    • 2017-01-27
    • 1970-01-01
    • 1970-01-01
    • 2018-03-20
    • 1970-01-01
    • 2014-09-07
    • 1970-01-01
    • 2011-09-20
    • 2013-01-05
    相关资源
    最近更新 更多