面试官:“Spring MVC怎么实现统一异常处理?”

在Web开发中,异常处理是保证系统健壮性的关键环节。但你是否遇到过这样的问题:Controller中每个方法都写try-catch处理异常,代码冗余且难以维护?Spring MVC提供了一套优雅的机制实现统一异常处理,既能避免代码重复,又能灵活控制异常响应。本文从源码层面解析其实现原理,助你彻底掌握这一核心技能!


一、Spring MVC统一异常处理的核心机制

1. 核心注解:@ControllerAdvice + @ExceptionHandler

  • @ControllerAdvice:标记一个类为全局异常处理器,可拦截所有Controller抛出的异常。

  • @ExceptionHandler:标记处理特定异常的方法,支持定义多种异常类型。

示例代码

@ControllerAdvice
public class GlobalExceptionHandler {
    
    // 处理所有NullPointerException
    @ExceptionHandler(NullPointerException.class)
    public ResponseEntity<String> handleNullPointer(NullPointerException ex) {
        return ResponseEntity.status(500).body("空指针异常:" + ex.getMessage());
    }
    
    // 处理所有其他异常
    @ExceptionHandler(Exception.class)
    public ResponseEntity<String> handleException(Exception ex) {
        return ResponseEntity.status(500).body("系统错误:" + ex.getMessage());
    }
}

二、源码解析:异常处理如何生效?

1. 核心接口:HandlerExceptionResolver

Spring MVC通过HandlerExceptionResolver接口处理Controller抛出的异常,其核心实现类是ExceptionHandlerExceptionResolver

源码入口DispatcherServletprocessHandlerException方法。

protected ModelAndView processHandlerException(HttpServletRequest request, HttpServletResponse response,
        Object handler, Exception ex) throws Exception {
    // 遍历所有注册的HandlerExceptionResolver
    for (HandlerExceptionResolver resolver : this.handlerExceptionResolvers) {
        ModelAndView mav = resolver.resolveException(request, response, handler, ex);
        if (mav != null) {
            return mav;
        }
    }
    throw ex;
}

2. @ExceptionHandler的底层实现

ExceptionHandlerExceptionResolver 负责处理带有@ExceptionHandler注解的方法。其核心逻辑如下:

  1. 扫描所有@ControllerAdvice:在应用启动时,通过ExceptionHandlerMethodResolver收集所有异常处理方法。

  2. 匹配异常类型:当Controller抛出异常时,根据异常类型找到最匹配的@ExceptionHandler方法。

  3. 反射调用处理方法:通过反射执行对应方法,生成响应结果。

源码片段

// ExceptionHandlerExceptionResolver 中处理异常
protected ModelAndView doResolveHandlerMethodException(HttpServletRequest request,
        HttpServletResponse response, HandlerMethod handlerMethod, Exception exception) {
    // 1. 查找匹配的@ExceptionHandler方法
    Method method = getExceptionHandlerMethod(handlerMethod, exception);
    // 2. 反射调用方法
    Object result = invokeMethod(method, handlerMethod, exception, request, response);
    // 3. 处理返回值(如ModelAndView、ResponseEntity等)
    return handleResult(request, response, result);
}

3. @ControllerAdvice的扫描机制

Spring通过ControllerAdviceBean类扫描所有标注@ControllerAdvice的类,并在容器启动时注册它们的异常处理方法。

源码关键逻辑

// ExceptionHandlerExceptionResolver 初始化时加载所有@ControllerAdvice
public void afterPropertiesSet() {
    List<ControllerAdviceBean> adviceBeans = ControllerAdviceBean.findAnnotatedBeans(getApplicationContext());
    for (ControllerAdviceBean adviceBean : adviceBeans) {
        // 解析每个@ControllerAdvice类中的@ExceptionHandler方法
        ExceptionHandlerMethodResolver resolver = new ExceptionHandlerMethodResolver(adviceBean.getBeanType());
        this.exceptionHandlerCache.put(adviceBean, resolver);
    }
}

三、其他异常处理方式

1. 实现HandlerExceptionResolver接口

自定义异常解析器,适合需要完全控制异常响应逻辑的场景。

@Component
public class CustomExceptionResolver implements HandlerExceptionResolver {
    @Override
    public ModelAndView resolveException(HttpServletRequest request, 
            HttpServletResponse response, Object handler, Exception ex) {
        if (ex instanceof CustomException) {
            response.setStatus(500);
            return new ModelAndView("error/custom"); // 返回自定义错误页面
        }
        return null; // 其他异常由其他解析器处理
    }
}

2. 使用SimpleMappingExceptionResolver

通过配置映射特定异常到错误页面,适合简单场景。

<bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
    <property name="exceptionMappings">
        <props>
            <prop key="java.lang.NullPointerException">error/npe</prop>
        </props>
    </property>
</bean>


四、最佳实践与避坑指南

1. 异常处理优先级

Spring MVC按以下顺序处理异常:

  1. @ExceptionHandler(当前Controller内) → 2. @ControllerAdvice → 3. HandlerExceptionResolver实现类 → 4. 默认错误页面

避坑:若自定义HandlerExceptionResolver返回非空结果,会中断后续处理!

2. 异常匹配规则

  • 精准匹配:优先匹配抛出异常的具体类型(如NullPointerException)。

  • 继承链匹配:若未找到具体类型,会向上匹配父类异常(如RuntimeException)。

示例:若同时定义@ExceptionHandler(NullPointerException.class)@ExceptionHandler(Exception.class),抛出NullPointerException时优先触发前者。

3. 返回值类型支持

@ExceptionHandler方法支持多种返回值:

  • ModelAndView:返回视图和模型数据。

  • ResponseEntity:灵活控制HTTP状态码和响应体。

  • @ResponseBody:直接返回JSON数据(需配合@RestControllerAdvice)。


五、总结

  • 核心机制@ControllerAdvice + @ExceptionHandler是Spring MVC统一异常处理的首选方案,基于ExceptionHandlerExceptionResolver实现。

  • 底层流程:DispatcherServlet捕获异常 → 遍历HandlerExceptionResolver → 反射调用匹配的@ExceptionHandler方法。

  • 灵活扩展:可通过自定义HandlerExceptionResolverSimpleMappingExceptionResolver满足不同需求。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

孙悟饭Z

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值