【问题标题】:Spring Global Exception Handler - Not MVCSpring 全局异常处理程序 - 不是 MVC
【发布时间】:2017-12-11 14:25:36
【问题描述】:

常规 Spring (Boot) 是否有办法进行全局异常处理,或者至少可以捕获任何未捕获的异常(例如可能随机发生的 RuntimeException)?

我在 Google 上四处搜索,但我发现的所有内容都涉及控制器的 @ControllerAdvice @ExceptionHandler。与一般的全局异常处理程序无关。

我基本上只是想确保如果发生一些我还没有捕捉到的异常,我会记录它以便我知道它。

【问题讨论】:

  • 阅读此stackoverflow.com/a/28678037/3959856 听起来就像@ControllerAdvice 就是这样。为什么不呢?
  • 还有ErrorControllerdocs.spring.io/spring-boot/docs/current/api/org/springframework/…,它只比ControllerAdvice或ExceptionHandler高一个级别。但不确定这是否是您想要的
  • @JackFlamp 我猜 OP 没有使用控制器,这就是为什么这种方法不起作用
  • 为什么不使用 Thread.UncaughtExceptionHandler?
  • @JackFlamp 正如 Lino 提到的,为此我没有使用控制器。我的特殊情况实际上是使用@Scheduled自动触发任务。

标签: java spring


【解决方案1】:

通过 AOP 添加你自己的,这样就可以了:

@Aspect
@Component
public class ExceptionHandler {

    @AfterThrowing(pointcut = "within(*.*)", throwing = "t")
    public void log(Throwable t) {
        t.printStackTrace();
    }
}

查看cheat sheet 以帮助找到切入点。

【讨论】:

  • 就像 OP 一样,我有一个不提供端点服务的 Spring 项目。我尝试将此添加到我的Thread.UncaughtExceptionHandler,但没有成功。
  • 虽然我实际上得到了formal unbound in pointcut,这意味着如果我能修复这方面的问题,这可能仍然有效。
【解决方案2】:

我认为 spring 没有为此提供开箱即用的解决方案。

实现这一点的一种可能性是使用带有注释的AOP(您可以在此处找到一个示例:Where can I catch non rest controller exceptions in spring?)。使用这种方法,您可以为使用预定义注释注释的所有方法定义一个全局切入点。这种方法的好处是将所有错误处理逻辑集中在一个地方。

【讨论】:

    【解决方案3】:

    最好扩展 Spring 的 ResponseEntityExceptionHandler 类并以您想要的方式自定义它,例如:

    import lombok.extern.slf4j.Slf4j;
    import org.springframework.http.HttpHeaders;
    import org.springframework.http.HttpStatus;
    import org.springframework.http.ResponseEntity;
    import org.springframework.lang.Nullable;
    import org.springframework.web.bind.annotation.ControllerAdvice;
    import org.springframework.web.bind.annotation.ExceptionHandler;
    import org.springframework.web.context.request.WebRequest;
    import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler;
    
    import javax.validation.ValidationException;
    
    @ControllerAdvice
    @Slf4j
    public class GlobalExceptionHandler extends ResponseEntityExceptionHandler {
    
        @ExceptionHandler(ValidationException.class)
        protected ResponseEntity<Object> handle(ValidationException ex) {
            return new ResponseEntity<>(getError(HttpStatus.BAD_REQUEST, ex), new HttpHeaders(), HttpStatus.BAD_REQUEST);
        }
    
        @ExceptionHandler
        protected ResponseEntity<Object> handle(Exception ex, WebRequest request) {
            try {
                return super.handleException(ex, request);
            } catch (Exception e) {
                return handleExceptionInternal(ex, null, new HttpHeaders(), HttpStatus.INTERNAL_SERVER_ERROR, request);
            }
        }
    
        @Override
        protected ResponseEntity<Object> handleExceptionInternal(Exception ex, @Nullable Object body, HttpHeaders headers, HttpStatus status, WebRequest request) {
            if (HttpStatus.Series.SERVER_ERROR == status.series()) {
                log.error("Unexpected error.", ex);
            }
            return new ResponseEntity<>(getError(status, ex), headers, status);
        }
    
        private ApiError getError(HttpStatus status, Exception ex) {
            return ApiError.builder()
                .status(status.value())
                .message(ex.getMessage())
                .build();
        }
    }
    

    这样您可以覆盖 Spring 的默认错误响应正文,声明您的自定义异常(例如 ValidationException)以及允许 Spring 处理其在 ResponseEntityExceptionHandler 中声明的默认异常。

    请注意,尽管在 Spring 4.x 中不需要围绕 super.handleException(ex, request) 进行 try-catch,但由于底层 ResponseEntityExceptionHandler 实现的更改,在 Spring 5.x 中是必需的。

    【讨论】:

    • OP 要求非 MVC 解决方案
    猜你喜欢
    • 2016-11-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-03-20
    • 2016-02-12
    • 1970-01-01
    • 2014-04-17
    • 2012-12-31
    相关资源
    最近更新 更多