在Spring应用程序中处理exception的位置
我还在学spring。 我有一个应用程序设置,我正在尝试理解Spring中的exception处理。
我正在使用@ControllerAdvice
来处理exception。 在我的应用程序中,有几个层,如Services
, Controllers
, Models
和Repositories
。 我应该在哪个层处理exception? 或者我应该在适当的时候处理每一层中的exception?
这是在Spring中启动exception处理的好方法:
步骤1 –创建特定的DefaultExceptionHandler类,并使用@ControllerAdvice批注对其进行批注。 在此处理程序类中,您有不同的方法,捕获预期和意外的exception,这些exception使用@ExceptionHandler批注进行批注:
@ControllerAdvice("com.stackoverflow.example") @SuppressWarnings("WeakerAccess") public class DefaultExceptionHandler extends ResponseEntityExceptionHandler { private final Logger log = LoggerFactory.getLogger("DefaultExceptionHandler"); private final MessageSourceAccessor messageSource; @Autowired public DefaultExceptionHandler(MessageSourceAccessor messageSource) { Assert.notNull(messageSource, "messageSource must not be null"); this.messageSource = messageSource; } @ExceptionHandler(ApplicationSpecificException.class) public ResponseEntity
第2步 –创建一个特定于应用程序的exception(ApplicationSpecificException类),用于预期的exception,并在任何级别抛出此exception,它将被Spring接收:
public class ApplicationSpecificException extends RuntimeException { private static final long serialVersionUID = 1L; private final ExceptionType exceptionType; public ApplicationSpecificException(ExceptionType exceptionType, Object... messageArguments) { super(MessageFormat.format(exceptionType.getMessage(), messageArguments)); this.exceptionType = exceptionType; } public ApplicationSpecificException(ExceptionType exceptionType, final Throwable cause, Object... messageArguments) { super(MessageFormat.format(exceptionType.getMessage(), messageArguments), cause); this.exceptionType = exceptionType; } public HttpStatus getHttpStatus() { return exceptionType.getStatus(); } public ExceptionType getExceptionType() { return exceptionType; } }
ExceptionType是一个枚举:
public enum ExceptionType { HTTP_INTERNAL_SERVER_ERROR(HttpStatus.INTERNAL_SERVER_ERROR, "An internal server error occurred."); //you can specify your own exception types... private HttpStatus status; private String message; ExceptionType(HttpStatus status, String message) { this.status = status; this.message = message; } public HttpStatus getStatus() { return status; } public String getMessage() { return message; } }
第3步 –最后,创建了一个ExceptionFactory类。 这允许您在应用程序日志中自动记录exception:
public class ExceptionFactory { private static final Logger LOG = LoggerFactory.getLogger(ExceptionFactory.class); public static ApplicationSpecificException create(final Throwable cause, final ExceptionType exceptionType, final Object... messageArguments) { LOG.error(MessageFormat.format(exceptionType.getMessage(), messageArguments), cause); return new ApplicationSpecificException (exceptionType, cause, messageArguments); } public static ApplicationSpecificException create(final ExceptionType exceptionType, final Object... messageArguments) { LOG.error(MessageFormat.format(exceptionType.getMessage(), messageArguments)); return new TerminologyServerException(exceptionType, messageArguments); } }
步骤4 –在应用程序的任何位置,您现在可以抛出exception,这将在应用程序日志中记录exception。 由于Spring @ControllerAdvice注释,DefaultExceptionHandler抛出并拾取此exception:
throw ExceptionFactory.create(ExceptionType.INTERNAL_SERVER_ERROR);
像这样,您应对exception处理流程作为一个跨领域的问题。 不会将内部服务器错误传播给最终用户,并且DefaultExceptionHandler会处理预期和意外exception。 exception被分配了一个HTTP错误代码和错误消息,它将返回给客户端。
使用@ControllerAdvice
注释的专用类可以处理所有意外问题,这是一个很好的做法。 通过这样做,您可以防止将应用程序的内部暴露给客户端。
@ControllerAdvice public class UncaughtExceptionHandler { private static final Logger log = LoggerFactory.getLogger(UncaughtExceptionHandler.class); @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR) @ExceptionHandler(Exception.class) public void handleAll(Exception e) { log.error("Unhandled exception occurred", e); } }
对于预期的exception (不要与已检查的exception混淆),您可能会在出现问题的地方处理问题。 一些exception可以传播或包装并重新抛出到与@ControllerAdvice
一样实现的同一个全局处理程序,以保持整个逻辑专用于单个点中的exception。
您应该尝试@ExceptionHandler
注释。
你可以在这里阅读更多相关信息: https : //spring.io/blog/2013/11/01/exception-handling-in-spring-mvc
您可以在Spring应用程序中使用@ControllerAdvice
作为全局exception处理程序。 检查这个很好解释教程。 使用@ControllerAdvice
可以减少您的业务代码的混乱,然后您可以在一个单独的位置处理所有exception。 @ControllerAdvice
使您坚持设计原则分离的关注点 。
使用Spring Framework有三种方法可以处理exception,
-
@ExceptionHandler – 基于控制器
这个处理程序是基于控制器的,我们需要有一个用@ExceptionHandler注释的方法,它接受Exception Class [你要处理的任何exception]作为参数,如果在控制器中引发任何这些exception,那么这个处理程序方法将处理。
如果我们在同一个控制器中有两个处理程序方法,比如说一个Exception处理程序和另一个RuntimeException处理程序,则会触发更接近Exception Class hirarchy的处理程序方法。 在这种情况下,抛出NullpointerException然后触发IOException处理程序方法,该方法最接近Exception类。
-
@ControllerAdvice – 全局exception处理程序
这用于Spring应用程序中的全局error handling。 您需要拥有的是使用@ControllerAdvice注释的类。 如果在定义的控制器中引发任何exception[您可以定义此控制器建议应该在哪些包中监听基本包中的exception],那么它将由ControllerAdvice处理。
您将在ControllerAdvice中拥有多个@ExceptionHandler,如下面的代码段所示。 此类可以是单个位置,您可以在其中处理整个应用程序的exception。
@ControllerAdvice(basePackages = "{com.exampe.controller}") public class RestApiExceptionHandlerAdvice { /** Handling Business exception */ @ExceptionHandler(value = BadRequestException.class) public ErrorMessage handleBadRequest(BadRequestException exception) { //code... return errMsg; } @ExceptionHandler(value = GatewayTimeoutException.class) public ErrorMessage handleGatewayTimeout(GatewayTimeoutException exception) { //code... return errMsg; } }
-
HandlerExceptionResolver
通过以上两种方法,我们大多数时候都使用静态页面。 在这种情况下,我们可以将不同的视图返回到不同的exception。 我们可以在spring.xml中使用MySimpleMappingExceptionResolver进行配置,您可以指定需要为哪个exception呈现哪个视图。