@ExceptionHandler的顺序

18

我使用@ControllerAdvice来处理我应用程序的所有异常:

我使用@ControllerAdvice来处理我应用程序的所有异常:

@ControllerAdvice
public class ExceptionHandlingController {

  @ExceptionHandler({UnauthorizedException.class})
  public String unauthorizedException()  {
        .........
  }


  @ExceptionHandler({UnauthorizedAjaxException.class})
  @ResponseBody
  public void unauthorizedAjaxException()  {
        .........
  }

  @ExceptionHandler({Exception.class})
  public String globalException(){
        .........
  }


}

在我的代码中某个地方,我会执行 throw new UnauthorizedException();

   @Around("@annotation(Authenticated)")
   public Object profilingAuthentication(ProceedingJoinPoint pjp) throws Throwable  {

       HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest();

       if( request.getSession().getAttribute("idContact") == null ) {
            if( "XMLHttpRequest".equals(request.getHeader("X-Requested-With")) )
                throw new UnauthorizedAjaxException();
            throw new UnauthorizedException();
       } 
       return pjp.proceed();
   }

不幸的是,Spring MVC 似乎会随机使用最常见的情况(Exception),而不是更具体的情况(例如UnauthorizedException)。有时他会选择正确的情况!

顺序是如何工作的?是否有任何指定顺序的方法?

UnauthorizedException是一个自定义异常

public class UnauthorizedException extends Exception {

    public UnauthorizedException(){
        super();
    }

    public UnauthorizedException(String message){
        super(message);
    }
}

更新

我发现订单实际上不是随机的,抛出UnauthorizedException异常的方法确实正常工作,但其他方法则不是!

@Authenticated
@RequestMapping(value="/favoris") 
public String favoris(ModelMap model, HttpServletRequest request) 
      throws UnauthorizedException {
    ....
}

@Authenticated
@RequestMapping(value="/follow") 
public String follow(ModelMap model, HttpServletRequest request) {
    .....
}

那么我必须手动添加 throws UnauthorizedException 还是有其他解决方案?


当你说对于不抛出UnauthorizedException的方法它不起作用时,这是什么意思?由于UnauthorizedException是自定义异常,你必须抛出它,否则应用程序如何为你抛出它呢? - Vinu Dominic
3个回答

1
使用注解@Order或实现接口Ordered来为@ControllerAdvice指定顺序。
参见以下实现:
  • ExceptionHandlerMethodResolver
  • ExceptionHandlerExceptionResolver类(方法initExceptionHandlerAdviceCache
  • AnnotationAwareOrderComparator

1
我们正在以下方式使用异常处理程序,并且订单从不混淆,它按预期工作。因此,如果您按照以下示例使用它,则可以解决您的问题。

处理程序类

@ControllerAdvice
public class GlobalExceptionHandler {

    @ResponseStatus(value = HttpStatus.INTERNAL_SERVER_ERROR)
    @ExceptionHandler(value = Exception.class)
    public boolean handle1(Exception exc) {
        System.out.println("#####Global Exception###" + exc);
        exc.printStackTrace(System.out);
        return true;
    }

    @ResponseStatus(value = HttpStatus.INTERNAL_SERVER_ERROR)
    @ExceptionHandler(value = CustomException.class)
    public boolean handle2(CustomException exc) {
        System.out.println("###custom exception######" + exc);
        exc.printStackTrace(System.out);
        return true;
    }
}

控制器类

@RestController("test")
@RequestMapping("/test1")
public class TestController {

    @RequestMapping("/t1")
    public boolean test() {
        if (true) {
            throw new CustomException();
        }
        return true;
    }
}

在上面的例子中,异常处理程序是 handle2,因为首先它将搜索匹配的异常,如果找不到,则转到父处理程序。
如果我们抛出新的 NullPointerException(),那么它将搜索匹配的处理程序,但在这种情况下没有找到,然后转到父处理程序,即 handle1
更多信息请参见此处
希望这可以帮助您。谢谢。

有人验证过并可以确认吗?有官方来源吗? - Peter Wippermann
据我所见,这是胡说八道。简而言之:将选择最具体的ExceptionHandler。 实际算法已在此处描述:https://dev59.com/UGIk5IYBdhLWcg3wMLmI#19500823。 - Peter Wippermann

0

只要您的项目中有一个单一的ControllerAdvice类,就没有顺序/优先级问题。但是如果您有多个ControllerAdvice类,则可以设置顺序。但在您的情况下,顺序不适用,因为这两个异常被处理方式不同(即UnauthorizedException和Exception)。

好消息是,Spring会自动查找相应的自定义异常类(如果有的话,否则是通用异常),并调用相应的方法。

请参阅有关Spring Controller Advice和异常处理的更多信息: https://spring.io/blog/2013/11/01/exception-handling-in-spring-mvc


你是在建议他们的应用程序应该有一个单独的@ExceptionHandler吗? - Sotirios Delimanolis
我并不建议完全采用单一的ExceptionHandler。 - developer
你能澄清一下如何设置订单吗?我想这就是他们所问的。 - Sotirios Delimanolis
1
通过你的所有编辑,似乎你的答案归结为“但是在这里,在你的情况下,顺序不适用,因为这两个异常处理方式不同”。但他们已经通过程序的行为知道了这一点。你是说没有办法设置那个顺序吗?你如何解释 OP 的说法,即行为有时会在处理程序之间交替? - Sotirios Delimanolis
1
@开发者 我不想使用多个ControllerAdvice类。 - Hayi
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接