Spring Boot 中处理异常的方法。抛出异常捕获并抛出相同的异常,这是一种不好的做法吗?

Approach to handle exception in Spring Boot. Throw exception catch and throw the same exception, is it a bad practice?

我正在使用 spring 启动,我正在处理异常处理的好方法:

我遇到过与存储库交互以获得产品的情况。但是,如果数据库出现连接问题怎么办,我不会捕获该异常

Product product = productRepository.findById(productId)
                .orElseThrow(() -> new NotFoundException("Could not find a product"));
try {
// Product logic
} catch(Exception e) {
            throw new ProductException(String.format("Error getting product productId=%s. Exception message: %s",
                    productId, e.getMessage()), e);
        }

我有一个控制器建议来捕获异常并且 return 一个很好的响应:

@ControllerAdvice
public class ExceptionHandler extends ResponseEntityExceptionHandler {
    @ExceptionHandler({NotFoundException.class})
    public ResponseEntity<Error> handleNotFoundException(HttpServletRequest request, Exception exception) {
    .....
}

我想我可以这样做:

    try {
        Product product = productRepository.findById(productId)
                    .orElseThrow(() -> new NotFoundException("Could not find a product"));
    } catch(NotFoundException e) {
        throw new NotFoundException(e.getMessage())
    } catch(Exception e) {
                throw new ProductException(String.format("Error getting product productId=%s. Exception message: %s",
                        productId, e.getMessage()), e);

这行得通,但看起来很奇怪,因为我抛出了两次 NotFoundException。有什么想法吗?

您仍然可以在 ControllerAdvice 中捕获它,即使您不抛出它,因此无需尝试捕获该异常而是添加:

@ExceptionHandler({PSQLException.class})

这是针对 Postgres 的,对于其他类型的数据库,您会有不同的异常,然后您也可以处理该消息,并在 ControllerAdvice

中查看其原因

一般来说,捕获异常并在之后立即再次抛出并没有什么奇怪的。例如,您可以捕获它以将其记录在某处,然后将其扔给下一个处理程序以进行实际处理(就像您的情况一样)。

你可以简单地写:

catch (NotFoundException e) {
    // Log if needed
    throw e; // <-- no need to build a new one
}

然而,对于后面的部分,捕获泛型 Exception 通常是一种不好的做法。这个异常的来源太多了,你不能就这么认为是因为数据库没有响应。

所以最好的办法是您的函数捕获它知道如何处理的内容,并抛出它不知道如何处理的内容。例如:

public void yourFunction() throws NotFoundException, ProductException {
    //you don't know how to handle NotFoundException and ProductException here, hence you throw them up
    try {
        // your logic
    } catch (SpecificExceptionYouWantToCatch e) {
        //handle specific exception you know how to handle
    } catch (AnotherSpecificException e) {
        //handle other specific exception you know how to handle
    }
    //Let all the other Runtime exceptions flow up to the caller. 
}

如果有异常,就是出错了。你不能只是把它包裹起来并假装它是一个 ProductException,所以:

  • 如果您识别出异常并知道如何处理它,那么就去做(就像您为 NotFoundException 所做的那样)
  • 但是,如果您没有预料到该异常,则最好顺其自然。在某些时候它会被捕获并处理,也许,或者可能只是让程序崩溃。但是你会想知道它,而如果你只是把它包装成一个 ProductException 你可能会向系统隐藏一个更大的问题。