跳至主要內容

springboot源码解析:用@RestControllerAdvice和@ExceptionHandler处理全局异常

程序员诚哥大约 6 分钟面试题springbootjava

摘要

本文讨论 Spring Boot 中的 @RestControllerAdvice 注解及其作用。@RestControllerAdvice 注解用于定义全局异常处理器和全局数据绑定设置。它标记的类可以处理全局范围内的异常,并根据定义的处理方法执行自定义逻辑。我们还探讨了 Spring 底层是如何实现和处理 @RestControllerAdvice 的。

Spring Boot 使用基于注解的配置方式,通过扫描和初始化标记了 @RestControllerAdvice 注解的类来创建全局异常处理器。该类中的方法使用 @ExceptionHandler 注解来标记,用于处理特定类型的异常。通过 AOP 和事件机制,Spring 在关键的处理流程中拦截、处理异常和数据绑定,并使用 @RestControllerAdvice 注解提供的机制来实现全局异常处理和数据绑定设置。

此外,我们还通过代码示例展示了如何实现全局异常处理和数据绑定。代码中使用了 HandlerExceptionResolver 接口和 HandlerMethodReturnValueHandler 接口来处理异常和处理器方法的返回值。

总结起来,@RestControllerAdvice 是 Spring Boot 提供的注解,用于实现全局范围内的异常处理和数据绑定设置。它基于 Spring MVC 的 HandlerExceptionResolverHandlerMethodReturnValueHandler 实现,并通过 AOP 和事件机制来拦截和处理异常。这种机制使得全局异常处理和数据绑定可以集中管理,并提供了灵活性和扩展性。

全局异常处理

@RestControllerAdvice 是 Spring Boot 中的注解,用于定义全局异常处理器和全局数据绑定设置。

它的作用是将一个类标记为全局异常处理器,并且同时结合 @ExceptionHandler 注解,可以定义一些方法来处理全局范围内的异常。当应用程序中抛出异常时,@RestControllerAdvice 注解会捕获这些异常,并根据定义的处理方法来处理它们。

使用 @RestControllerAdvice 注解的类通常是一个带有异常处理方法的类,这些方法使用 @ExceptionHandler 注解来指定要处理的特定异常类型。当应用程序中抛出相应的异常时,异常处理方法会被调用,并可以执行一些自定义的逻辑,例如记录异常、返回特定的错误信息等。

下面是一个简单的示例,展示了 @RestControllerAdvice 注解的使用:

@RestControllerAdvice
public class GlobalExceptionHandler {

    @ExceptionHandler(Exception.class)
    public ResponseEntity<String> handleException(Exception ex) {
        // 处理异常的逻辑
        // 返回自定义的错误响应
        return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body("Internal Server Error");
    }
}

在上面的示例中,GlobalExceptionHandler 类使用 @RestControllerAdvice 注解进行标记,并定义了一个 handleException 方法,用于处理 Exception 类型的异常。当应用程序中抛出 Exception 异常时,该方法会被调用,并返回一个自定义的错误响应。

通过 @RestControllerAdvice 注解,我们可以集中管理应用程序中的异常处理逻辑,并在一个地方定义通用的错误处理方式。这样可以提高代码的可维护性和复用性,同时还能提供统一的错误处理体验。

Spring底层实现

Spring 框架的核心是基于事件驱动的、面向切面编程的思想。@RestControllerAdvice 的实现是基于 Spring MVC 模块,并通过 AOP(面向切面编程)和事件机制来实现全局异常处理和数据绑定设置。

在 Spring MVC 中,请求的处理流程包括多个环节,例如请求的分发、处理器的执行、视图的渲染等。@RestControllerAdvice 注解的实现主要涉及到两个关键组件:HandlerExceptionResolver(处理器异常解析器)和 HandlerMethodReturnValueHandler(处理器方法返回值处理器)。

  1. HandlerExceptionResolver:
    HandlerExceptionResolver 是 Spring MVC 中用于解析处理器(Controller)执行过程中出现的异常的接口。当请求处理器执行过程中抛出异常时,Spring MVC 会将异常交给 HandlerExceptionResolver 进行处理。而 @RestControllerAdvice 注解则提供了一种方式,可以注册一个自定义的 HandlerExceptionResolver,将其作为全局异常处理器。

@RestControllerAdvice 注解会扫描标注有 @ExceptionHandler 注解的方法,并将其包装为一个特殊的 ExceptionHandlerExceptionResolver 对象,注册到 Spring MVC 的异常处理器链中。当请求处理过程中发生匹配的异常时,ExceptionHandlerExceptionResolver 将会调用对应的方法来处理异常,并返回处理结果。

  1. HandlerMethodReturnValueHandler:
    HandlerMethodReturnValueHandler 是 Spring MVC 中用于处理处理器方法返回值的接口。当处理器方法执行完毕后,Spring MVC 会将处理器方法的返回值交给 HandlerMethodReturnValueHandler 进行处理,进而将返回值转换为最终的响应结果。

@RestControllerAdvice 注解也可以使用 @ModelAttribute@InitBinder 等注解来处理全局数据绑定设置。这些注解可以标记在类的方法上,用于在请求处理过程中对模型属性和表单数据进行全局的预处理和绑定。

通过使用 AOP 和事件机制,Spring 在关键的处理流程中拦截、处理异常和数据绑定,并使用 @RestControllerAdvice 注解提供的机制来实现全局范围的异常处理和数据绑定设置。这种方式使得全局异常处理和数据绑定可以集中管理,并提供了灵活性和扩展性。

Spring伪代码

要理解 Spring 底层是如何实现和处理 @RestControllerAdvice,需要涉及较为复杂的 Spring MVC 框架内部逻辑和代码。以下是一个简化的示例,展示了 Spring 底层是如何处理 @RestControllerAdvice 注解的:

  1. HandlerExceptionResolver 的实现示例:
public class RestControllerAdviceExceptionResolver implements HandlerExceptionResolver {

    @Override
    public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
        if (handler instanceof HandlerMethod) {
            HandlerMethod handlerMethod = (HandlerMethod) handler;
            if (handlerMethod.hasMethodAnnotation(ExceptionHandler.class)) {
                ExceptionHandler exceptionHandlerAnnotation = handlerMethod.getMethodAnnotation(ExceptionHandler.class);
                // 获取异常处理方法
                Method exceptionHandlerMethod = handlerMethod.getMethod();
                // 调用异常处理方法,处理异常并返回结果
                Object result = invokeExceptionHandler(exceptionHandlerMethod, ex);
                // 返回处理结果
                return new ModelAndView(new MappingJackson2JsonView(), Collections.singletonMap("result", result));
            }
        }
        return null;
    }

    private Object invokeExceptionHandler(Method exceptionHandlerMethod, Exception ex) {
        try {
            // 通过反射调用异常处理方法,传入异常参数
            return exceptionHandlerMethod.invoke(exceptionHandlerMethod.getDeclaringClass().newInstance(), ex);
        } catch (Exception e) {
            // 处理异常处理方法调用失败的情况
            return null;
        }
    }
}

在上面的示例中,RestControllerAdviceExceptionResolver 实现了 HandlerExceptionResolver 接口。它会在异常发生时判断处理器方法是否有 @ExceptionHandler 注解,并调用相应的异常处理方法来处理异常,并返回处理结果。

  1. HandlerMethodReturnValueHandler 的实现示例:
public class RestControllerAdviceReturnValueHandler implements HandlerMethodReturnValueHandler {

    @Override
    public boolean supportsReturnType(MethodParameter returnType) {
        return returnType.hasMethodAnnotation(ModelAttribute.class) || returnType.hasMethodAnnotation(InitBinder.class);
    }

    @Override
    public void handleReturnValue(Object returnValue, MethodParameter returnType, ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception {
        // 处理返回值并设置到 ModelAndViewContainer 中
        mavContainer.addAttribute("result", returnValue);
    }
}

在上面的示例中,RestControllerAdviceReturnValueHandler 实现了 HandlerMethodReturnValueHandler 接口。它会判断处理器方法的返回类型是否带有 @ModelAttribute@InitBinder 注解,并将返回值设置到 ModelAndViewContainer 中,以便后续视图渲染时使用。

在实际使用中,你需要配置这些自定义的解析器和处理器,并将它们注册到 Spring MVC 中,使其生效。具体的配置方式取决于你使用的 Spring 版本和配置方式。

需要注意的是,上述代码仅为示例,实际的 Spring MVC 框架内部逻辑更为复杂,包括多个解析器、处理器的协同工作,以及异常处理的细节等。这里只是简化的展示了实现思路和关键部分的代码。

上次编辑于:
贡献者: zccbbg