Spring MVC 完整生命周期和异常处理流程图

news/2024/11/6 0:48:26 标签: spring, mvc, 流程图

先要明白
在这里插入图片描述

// 1. 用户发来请求: localhost:8080/user/1

// 2. 处理器映射器(HandlerMapping)的工作
// 它会找到对应的Controller和方法
@GetMapping("/user/{id}")  
public User getUser(@PathVariable Long id) {
    return userService.getById(id);
}

// 3. 处理器适配器(HandlerAdapter)的工作
// - 把URL中的"1"转成Long类型的1 (类型转换)
// - 检查id是否为空、是否是正数 (数据验证)
// - 把转换好的参数传给controller方法 (参数解析)
客户端/浏览器 前端控制器 (DispatcherServlet) 处理器映射器 (HandlerMapping) 处理器适配器 (HandlerAdapter) 控制器 (Controller) 服务层 (Service) 异常通知器 (@RestControllerAdvice) 异常解析器 (HandlerExceptionResolver) 前端控制器初始化 1. initMultipartResolver() 初始化文件上传解析器 2. initLocaleResolver() 初始化地区解析器 3. initThemeResolver() 初始化主题解析器 4. initHandlerMappings() 初始化处理器映射器 5. initHandlerAdapters() 初始化处理器适配器 6. initHandlerExceptionResolvers() 初始化异常解析器 请求处理阶段 1. 发送HTTP请求 (例如:POST /serve/onSale/1) 2. getHandler() 查找处理器 根据URL匹配HandlerMapping 返回HandlerExecutionChain 返回处理器执行链 3. getHandlerAdapter() 获取处理器适配器 适配器负责: 1.参数解析 2.类型转换 3.数据验证 返回适配器 业务处理阶段 4. handle(request, response, handler) 调用控制器方法 调用服务层方法 返回处理结果 返回ModelAndView 返回ModelAndView 业务处理出现异常 可能抛出: 1. ForbiddenOperationException 2. CommonException 3. 其他异常 异常被@RestControllerAdvice捕获 委托给异常解析器处理 异常解析过程: 1. 判断异常类型 2. 选择处理策略 3. 转换为统一响应 处理FeignException 处理CommonException 处理普通Exception alt [Feign调用异常] [自定义业务异常] [其他异常] 返回处理结果 返回错误响应 alt [正常业务流程] [异常流程] 响应处理阶段 processDispatchResult() 处理ModelAndView 返回处理结果 处理错误视图 返回统一错误格式 alt [成功响应] [错误响应] 核心组件说明: 1. DispatcherServlet:Spring MVC的核心,统一的请求处理入口 2. HandlerMapping:负责URL与处理器的映射 3. HandlerAdapter:负责适配不同类型的处理器 4. Controller:处理具体的业务逻辑 5. @RestControllerAdvice:统一的异常处理切面 6. HandlerExceptionResolver:负责具体的异常处理策略 客户端/浏览器 前端控制器 (DispatcherServlet) 处理器映射器 (HandlerMapping) 处理器适配器 (HandlerAdapter) 控制器 (Controller) 服务层 (Service) 异常通知器 (@RestControllerAdvice) 异常解析器 (HandlerExceptionResolver)
重要说明
响应处理阶段
异常处理阶段
业务处理阶段
请求处理阶段
前端控制器初始化阶段
找到
未找到
支持
不支持
成功
失败
Feign异常
业务异常
其他异常
前端控制器
DispatcherServlet
处理器映射器
HandlerMapping
处理器适配器
HandlerAdapter
异常通知器
@RestControllerAdvice
异常解析器
HandlerExceptionResolver
构建响应对象
返回HTTP响应
检查异常类型
FeignException处理
CommonException处理
Exception处理
是否内部调用
内部异常处理
外部异常处理
设置异常头信息
构建错误响应
调用服务层方法
是否成功
返回处理结果
抛出异常
查找处理器
接收HTTP请求
获取处理器适配器
返回404
适配器是否支持
调用控制器方法
返回错误信息
初始化文件上传解析器
initMultipartResolver
前端控制器初始化
初始化地区解析器
initLocaleResolver
初始化主题解析器
initThemeResolver
初始化处理器映射器
initHandlerMappings
初始化处理器适配器
initHandlerAdapters
初始化异常解析器
initHandlerExceptionResolvers
开始
结束

我用生活中的例子解释 @RestControllerAdvice 的工作原理:
想象一个大型商场的客服中心:

  1. DispatcherServlet就像商场的总服务台
  • 负责接收所有顾客的需求并分配给相应的专柜处理
  1. @RestControllerAdvice就像商场的客服中心
  • 设立在商场的一个统一位置
  • 专门处理各个专柜出现的问题和投诉

举个具体场景:

顾客在商场购物的流程:

1. 正常流程:
顾客 -> 总服务台(DispatcherServlet) -> 专柜(Controller) -> 购买商品

2. 出现问题时:
专柜(Controller)出现问题 -> 客服中心(@RestControllerAdvice)接手处理 -> 给顾客一个合理解释

用代码表示:

// 这就像设立一个统一的客服中心
@RestControllerAdvice
public class GlobalExceptionHandler {
    
    // 这就像专门处理"商品缺货"的客服人员
    @ExceptionHandler(ProductOutOfStockException.class)
    public ResponseEntity<String> handleOutOfStock(ProductOutOfStockException e) {
        // 返回友好提示:"非常抱歉,商品暂时缺货,预计3天后到货"
        return ResponseEntity.status(HttpStatus.BAD_REQUEST)
                           .body("商品暂时缺货,预计3天后到货");
    }
    
    // 这就像处理"商品价格异常"的客服人员
    @ExceptionHandler(PriceException.class)
    public ResponseEntity<String> handlePriceError(PriceException e) {
        // 返回友好提示:"价格显示异常,请稍后重试"
        return ResponseEntity.status(HttpStatus.BAD_REQUEST)
                           .body("价格显示异常,请稍后重试");
    }
}

为什么能拦截异常?
就像商场里:

  1. 所有专柜都在商场里面
  2. 客服中心在商场的入口处
  3. 一旦专柜出问题,就会按照商场规定,统一转到客服中心处理

在Spring中:

  1. DispatcherServlet(总服务台)知道有这个@RestControllerAdvice(客服中心)的存在
  2. 当Controller(专柜)抛出异常时
  3. DispatcherServlet就会把异常转给@RestControllerAdvice处理

关键点:

  • 它不是拦截,而是异常发生后的统一处理
  • Spring框架帮我们做了这个转发操作
  • 这样我们就不用在每个Controller里写重复的异常处理代码
客户端 DispatcherServlet Controller @RestControllerAdvice 异常通知类 @ExceptionHandler 异常处理方法 正常请求流程 1. 发送HTTP请求 2. 转发到Controller 异常发生和处理流程 3. 业务处理过程中抛出异常 @RestControllerAdvice的作用 1. 是@ControllerAdvice的特殊形式 2. 会自动扫描所有Controller 3. 集中处理所有异常 4. 异常被@RestControllerAdvice捕获 @ExceptionHandler的作用 1. 指定要处理的异常类型 2. 根据异常类型匹配处理方法 3. 将异常转换为友好响应 5. 根据异常类型找到对应的处理方法 处理微服务调用异常 处理业务异常 处理未知异常 alt [FeignExcept- ion异常] [CommonExc- eption异常] [其他Exceptio- n] 响应处理 6. 返回处理后的Result对象 7. 转换为HTTP响应返回 重要说明: 1. @RestControllerAdvice相当于异常的"统一接待处" 2. @ExceptionHandler相当于不同类型异常的"专门处理窗口" 3. 整个过程自动完成,使异常处理从业务代码中解耦 客户端 DispatcherServlet Controller @RestControllerAdvice 异常通知类 @ExceptionHandler 异常处理方法

http://www.niftyadmin.cn/n/5739972.html

相关文章

Logstash 安装与部署(无坑版)

下载 版本对照关系&#xff1a;ElasticSearch 7.9.2 和 Logstash 7.9.2 &#xff1b; 官方下载地址 选择ElasticSearch版本一致的Logstash版本 https://www.elastic.co/cn/downloads/logstash 下载链接&#xff1a;https://artifacts.elastic.co/downloads/logstash/logst…

vue3 怎么判断数据列是否包某一列名

在 Vue 3 中&#xff0c;你可以使用数组的 some 方法来判断一个数组是否包含某个特定的对象&#xff0c;例如某个列。some 方法会遍历数组中的每一个元素&#xff0c;如果找到符合条件的元素&#xff0c;则返回 true&#xff0c;否则返回 false tableProps.columns.some(column…

Python | Leetcode Python题解之第537题复数乘法

题目&#xff1a; 题解&#xff1a; class Solution:def complexNumberMultiply(self, num1: str, num2: str) -> str:real1, imag1 map(int, num1[:-1].split())real2, imag2 map(int, num2[:-1].split())return f{real1 * real2 - imag1 * imag2}{real1 * imag2 imag1…

【python】OpenCV—findContours(4.3)

文章目录 1、功能描述2、代码实现3、完整代码4、结果展示5、涉及到的库函数5.1、cv2.Canny5.2 cv2.boxPoints 6、参考 1、功能描述 找出图片中的轮廓&#xff0c;拟合轮廓外接椭圆和外接矩阵 2、代码实现 导入必要的库&#xff0c;固定好随机种子 import cv2 as cv import …

鸿蒙内核论文阅读总结概述

原文链接&#xff1a; https://www.usenix.org/system/files/osdi24-chen-haibo.pdf “Microkernel Goes General: Performance and Compatibility in the HongMeng Production Microkernel” 由 Haibo Chen 等人撰写&#xff0c;介绍了鸿蒙内核&#xff08;HM&#xff09;的设…

Android 15 在状态栏时间中显示秒数

这是更新后的博客草稿,关于在Android 15状态栏中显示秒数的实现: 在Android 15状态栏中显示秒数 在Android 15中,您可以通过两种方式在状态栏中显示秒数:使用ADB命令或修改系统源代码。下面详细介绍这两种方法。 方法一:通过ADB实现 您可以使用ADB(Android调试桥)命令…

Kafka 之批量消息发送消费

前言&#xff1a; 前面我们分享了 Kafka 的一些基础知识&#xff0c;以及 Spring Boot 集成 Kafka 完成消息发送消费&#xff0c;本篇我们来分享一下 Kafka 的批量消息发送消费。 Kafka 系列文章传送门 Kafka 简介及核心概念讲解 Spring Boot 整合 Kafka 详解 Kafka Kafka…

动态规划 —— dp问题-按摩师

1. 按摩师 题目链接&#xff1a; 面试题 17.16. 按摩师 - 力扣&#xff08;LeetCode&#xff09;https://leetcode.cn/problems/the-masseuse-lcci/description/ 2. 算法原理 状态表示&#xff1a;以某一个位置为结尾或者以某一个位置为起点 dp[i]表示&#xff1a;选择到i位置…