首页 > 其他分享 >Spring Boot 全局异常捕获机制详解

Spring Boot 全局异常捕获机制详解

时间:2024-07-01 14:53:48浏览次数:16  
标签:Exception Spring Boot request 详解 ex null 异常 response

在 Spring Boot 中,全局异常捕获机制是处理 REST HTTP 请求时的一个重要功能,它可以确保所有未被捕获的异常都能被统一处理。本文将深入探讨 Spring Boot 中全局异常捕获的实现,从请求进入到异常处理的全过程。

请求处理流程概述

  1. 请求进入 DispatcherServlet:所有 HTTP 请求首先到达 DispatcherServlet
  2. 调用处理器方法DispatcherServlet 调用相应的处理器方法(Controller 方法)。
  3. 异常捕获:如果在处理器方法中抛出异常,DispatcherServlet 会调用异常处理方法。
  4. 调用 HandlerExceptionResolver:调用所有注册的 HandlerExceptionResolver 来处理异常。
  5. 默认错误处理:如果所有的 HandlerExceptionResolver 都没有处理该异常,最终会由 BasicErrorController 来处理。

1. 请求进入 DispatcherServlet

在 Spring MVC 中,DispatcherServlet 是核心组件,负责接收请求并将其分发到相应的处理器。在 DispatcherServlet 中,doService 方法是处理请求的起点:

public class DispatcherServlet extends FrameworkServlet {

    @Override
    protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {
        try {
            doDispatch(request, response);
        } catch (Exception ex) {
            processHandlerException(request, response, null, ex);
        }
    }
}

2. 请求分发与异常捕获

doService 方法调用了 doDispatch 方法,doDispatch 是请求分发的核心方法,它会调用具体的处理器方法。如果在处理过程中抛出异常,doDispatch 会捕获该异常:

protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
    HttpServletRequest processedRequest = request;
    HandlerExecutionChain mappedHandler = null;
    boolean multipartRequestParsed = false;

    WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);

    try {
        ModelAndView mv = null;
        Exception dispatchException = null;

        try {
            // 调用处理器方法
            mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
        } catch (Exception ex) {
            dispatchException = ex;
        } catch (Throwable err) {
            dispatchException = new NestedServletException("Handler dispatch failed", err);
        }

        processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
    } catch (Exception ex) {
        triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
    } catch (Throwable err) {
        triggerAfterCompletion(processedRequest, response, mappedHandler,
                new NestedServletException("Handler processing failed", err));
    } finally {
        if (asyncManager.isConcurrentHandlingStarted()) {
            if (mappedHandler != null) {
                mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
            }
        } else {
            if (multipartRequestParsed) {
                cleanupMultipart(processedRequest);
            }
        }
    }
}

3. 处理异常结果

processDispatchResult 方法根据处理结果和异常状态决定接下来的操作:

private void processDispatchResult(HttpServletRequest request, HttpServletResponse response,
                                   HandlerExecutionChain mappedHandler, ModelAndView mv, Exception exception) throws Exception {
    boolean errorView = false;

    if (exception != null) {
        if (exception instanceof ModelAndViewDefiningException) {
            mv = ((ModelAndViewDefiningException) exception).getModelAndView();
        } else {
            mv = processHandlerException(request, response, mappedHandler.getHandler(), exception);
            errorView = (mv != null);
        }
    }

    if (mv != null && !mv.wasCleared()) {
        render(mv, request, response);
    } else {
        if (errorView) {
            response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
        }
    }
}

4. 调用 HandlerExceptionResolver

processHandlerException 方法会遍历所有的 HandlerExceptionResolver 来处理异常:

protected ModelAndView processHandlerException(HttpServletRequest request, HttpServletResponse response,
                                               Object handler, Exception ex) throws Exception {
    ModelAndView exMv = null;
    for (HandlerExceptionResolver resolver : this.handlerExceptionResolvers) {
        exMv = resolver.resolveException(request, response, handler, ex);
        if (exMv != null) {
            break;
        }
    }
    if (exMv != null) {
        return exMv;
    } else {
        throw ex;
    }
}

5. ExceptionHandlerExceptionResolver 处理自定义异常

ExceptionHandlerExceptionResolver 是处理通过 @ExceptionHandler 注解定义的异常处理方法的核心类:

public class ExceptionHandlerExceptionResolver extends AbstractHandlerMethodExceptionResolver {
    @Override
    protected ModelAndView doResolveHandlerMethodException(HttpServletRequest request, HttpServletResponse response,
                                                           HandlerMethod handlerMethod, Exception exception) {
        InvocableHandlerMethod exceptionHandlerMethod = getExceptionHandlerMethod(handlerMethod, exception);
        if (exceptionHandlerMethod != null) {
            try {
                return exceptionHandlerMethod.invokeAndHandle(webRequest, mavContainer, exception);
            } catch (Exception ex) {
                logger.error("Failed to invoke @ExceptionHandler method", ex);
            }
        }
        return null;
    }
}

6. 默认错误处理 BasicErrorController

如果所有的 HandlerExceptionResolver 都没有处理该异常,最终会由 BasicErrorController 来处理:

@Controller
@RequestMapping("${server.error.path:${error.path:/error}}")
public class BasicErrorController implements ErrorController {

    @RequestMapping
    public ResponseEntity<Map<String, Object>> error(HttpServletRequest request) {
        Map<String, Object> body = getErrorAttributes(request, isIncludeStackTrace(request, MediaType.ALL));
        HttpStatus status = getStatus(request);
        return new ResponseEntity<>(body, status);
    }

    protected HttpStatus getStatus(HttpServletRequest request) {
        Integer statusCode = (Integer) request.getAttribute("javax.servlet.error.status_code");
        if (statusCode == null) {
            return HttpStatus.INTERNAL_SERVER_ERROR;
        }
        try {
            return HttpStatus.valueOf(statusCode);
        } catch (Exception ex) {
            return HttpStatus.INTERNAL_SERVER_ERROR;
        }
    }
}

ENd

通过以上分析,我们可以清晰地看到 Spring Boot 中全局异常捕获的整个过程:

  1. 请求进入 DispatcherServlet
  2. 调用处理器方法
  3. 捕获处理器方法抛出的异常
  4. 调用 HandlerExceptionResolver 来处理异常。
  5. 如果异常没有被处理,最终由 BasicErrorController 处理

这种机制确保了在处理请求过程中,所有未被捕获的异常都能被统一处理,提高了应用的健壮性和可维护性。

通过对 DispatcherServletHandlerExceptionResolverBasicErrorController 的源码分析,我们可以深入理解 Spring Boot 的异常处理机制,帮助开发者在实际项目中更好地应用这一机制。

标签:Exception,Spring,Boot,request,详解,ex,null,异常,response
From: https://www.cnblogs.com/irobotzz/p/18278004

相关文章

  • BEV感知算法:LSS论文与代码详解
    BEV感知算法:LSS论文与代码详解0. 前言最近几年,BEV感知是自动驾驶领域中一个非常热门研究方向,其核心思想是把多路传感器的数据转换到统一的BEV空间中去提取特征,实现目标检测、地图构建等任务。如何把多路相机的数据从二维的图像视角转换到三维的BEV视角?LSS提出一种显示估......
  • DWA(Dynamic Window Approach)局部路径规划算法详解及代码实现
    DWA(Dynamic Window Approach)局部路径规划算法详解及代码实现二、算法原理一句话概况,就是假定机器人当前以若干组容许范围内的速度(差速轮为例:线速度V,角速度W)进行移动,并对这若干组速度进行轨迹计算,得到若干组轨迹,再根据若干条评分机制选择最好的轨迹所对应的速度作为dwa输......
  • springboot+vue+mybatis农业信息管理_种植员+PPT+论文+讲解+售后
    网络的广泛应用给生活带来了十分的便利。所以把农业信息管理与现在网络相结合,利用java技术建设农业信息管理系统,实现农业信息管理的信息化。则对于进一步提高农业信息管理发展,丰富农业信息管理经验能起到不少的促进作用。农业信息管理系统能够通过互联网得到广泛的、全面的宣......
  • springboot+vue+mybatis奶茶管理系统+PPT+论文+讲解+售后
    由于科学技术的快速发展,人们的生活也与信息时代的发展相关。同时,随着市场化和经济化的发展,国内很多行业已经意识到了这一点,为了提升行业的竞争力,就应当率先把握机会。于是在互联网的默化潜移影响下,餐饮业相关网站就是在这种情况下产生和发展起来的。奶茶在线订购系统是一个面......
  • springBoot集成Spring Cloud Alibaba Sentinel
    一、背景介绍:Sentinel·alibaba/spring-cloud-alibabaWiki·GitHub二、Sentinel介绍随着微服务的流行,服务和服务之间的稳定性变得越来越重要。 Sentinel 以流量为切入点,从流量控制、熔断降级、系统负载保护等多个维度保护服务的稳定性。Sentinel 具有以下特征:......
  • Dubbo 协议详解
    Solomon_肖哥弹架构跟大家“弹弹”分布式微服务Dubbo协议详解欢迎点赞,收藏,关注。关注本人的公众号Solomon肖哥弹架构获取更多的惊喜协议的概念协议是两个网络实体进行通信的基础,数据在网络上从一个实体传输到另一个实体,以字节流的形式传递到对端。在这个字节流的......
  • 1974Springboot医院远程诊断管理系统idea开发mysql数据库web结构java编程计算机网页源
    一、源码特点 springboot医院远程诊断管理系统是一套完善的信息系统,结合springboot框架和bootstrap完成本系统,对理解JSPjava编程开发语言有帮助系统采用springboot框架(MVC模式开发),系统具有完整的源代码和数据库,系统主要采用B/S模式开发。springboot医院远程诊断系统......
  • 基于Springboot的电子招投标系统。Javaee项目,springboot项目。
    演示视频:基于Springboot的电子招投标系统。Javaee项目,springboot项目。项目介绍:采用M(model)V(view)C(controller)三层体系结构,通过Spring+SpringBoot+Mybatis+Vue+Maven+Layui+Elementui来实现。MySQL数据库作为系统数据储存平台,实现了基于B/S结构的Web系统。界面简......
  • 基于Springboot的书籍学习平台(有报告)。Javaee项目,springboot项目。
    演示视频:基于Springboot的书籍学习平台(有报告)。Javaee项目,springboot项目。项目介绍:采用M(model)V(view)C(controller)三层体系结构,通过Spring+SpringBoot+Mybatis+Vue+Maven+Layui+Elementui来实现。MySQL数据库作为系统数据储存平台,实现了基于B/S结构的Web系统。界......
  • c指针详解(2)--- 指针与数组
    在大致了解了c语言中变量在内存中的分配、存活等方面后,我们再来看看数组在内存中又是如何呈现的。这里我们就只讨论静态数组,动态数组涉及到动态内存分配,这里就不详细展开了。那么什么是静态数组呢?要理解这个数据结构,我们可以将其切分为两个概念:静态与数组。数组:数组其实就是一......