Spring MVC 请求生命周期
侧边栏壁纸
  • 累计撰写 36 篇文章
  • 累计收到 1 条评论

Spring MVC 请求生命周期

ASN__
2026-06-10 / 0 评论 / 9 阅读 / 正在检测是否收录...

Spring MVC 请求生命周期

SpringBoot 2.7 + Java8 企业级开发

一、整体架构图 —— 一次请求的完整流水线

HTTP Request  -> http://你的项目/getUser?id=1
      │
      ▼
┌─────────────────────┐
│      Tomcat         │   内嵌 Servlet 容器,最早接收请求
│ Servlet Container   │
└─────────────────────┘
      │
      ▼
┌─────────────────────┐
│ Filter 过滤器链      │   Servlet 级别的“门卫”,工作在 Spring MVC 之前
└─────────────────────┘
      │
      ▼
┌─────────────────────┐
│ DispatcherServlet   │   Spring MVC 的“总控”,分发请求的核心
└─────────────────────┘
      │
      ▼
┌─────────────────────┐
│ HandlerInterceptor  │   Spring 自己的拦截器,更懂 Controller
│ preHandle           │   请求到达 Controller 前执行
└─────────────────────┘
      │
      ▼
┌─────────────────────┐
│ Controller          │   你写的接口,@RestController / @GetMapping
└─────────────────────┘
      │
      ▼
┌─────────────────────┐
│ Service             │   业务逻辑层
└─────────────────────┘
      │
      ▼
┌─────────────────────┐
│ DAO/JdbcTemplate    │   数据访问层,执行 SQL
└─────────────────────┘
      │
      ▼
┌─────────────────────┐
│ MySQL               │   数据库
└─────────────────────┘
      │
      ▼
Controller返回结果    返回 Java 对象
      │
      ▼
Interceptor.postHandle   所有拦截器的 postHandle
      │
      ▼
ViewResolver   /  JSON序列化   前后端分离时转成 JSON 字符串
      │
      ▼
Interceptor.afterCompletion  资源清理、日志记录
      │
      ▼
Response  → 浏览器

二、企业项目真实执行顺序(必背)

虚假的顺序:

Tomcat -> Interceptor -> Controller

实际严格顺序:

Tomcat -> Filter -> DispatcherServlet -> Interceptor -> Controller -> Service -> DAO -> MySQL

为什么是这个顺序?

  • Filter 是 Servlet 规范 定义的,工作在容器级别,比 Spring 更底层;
  • Interceptor 是 Spring MVC 内部 的,只有在 DispatcherServlet 接收请求之后才生效。
  • 也就是说:Filter 可以拦截所有请求(包括静态资源),而 Interceptor 只能拦截进入 Spring MVC 的请求。

三、Filter 和 Interceptor 区别 —— 两个不同级别的“保安”

1. Filter(Servlet 级别)

  • 定义方式:实现 javax.servlet.Filter 接口
  • 执行时机Tomcat → Filter → Spring MVC
  • 特点:工作在容器层,不依赖 Spring,拿不到 Controller、方法等 Spring 上下文信息。
  • 典型用途

    • JWT 登录校验(直接解析 token,失败直接返回 401)
    • XSS 过滤(清洗 <script> 等危险字符)
    • 请求日志(记录每个请求的耗时、URL)
    • 跨域处理(CorsFilter 统一设置响应头)

      2. Interceptor(Spring MVC 级别)

  • 定义方式:实现 org.springframework.web.servlet.HandlerInterceptor 接口
  • 执行时机DispatcherServlet → Interceptor → Controller
  • 特点:能获取到 Handler(Controller 方法)、参数、返回结果等,是 Spring 生态内的拦截手段。
  • 典型用途

    • 用户信息注入(从 token 解析用户信息,放入 UserContext
    • 权限校验(admin / user 角色判断)
    • 操作日志(记录“谁在何时做了什么”)
    • API 访问统计(PV / UV 计数)

      面试标准答案

      Filter 先执行,Interceptor 后执行。
      Filter 是 Servlet 规范,Intercetpor 是 Spring MVC 专属。

      四、DispatcherServlet 到底干了什么 —— 核心方法 doDispatch()

      设计模式:前端控制器模式(Front Controller Pattern)
      所有请求都会先被 DispatcherServlet 接管,它自己不干活,只负责指挥
      源码简化流程:

      doDispatch() {
      // 1. 根据请求找到 Handler(Controller 方法)并包装成 HandlerExecutionChain
      HandlerExecutionChain chain = getHandler(request);
      // 2. 执行所有拦截器的 preHandle
      chain.applyPreHandle(request, response);
      // 3. 真正调用 Controller 方法
      HandlerAdapter adapter = getHandlerAdapter(handler);
      ModelAndView mv = adapter.handle(request, response, handler);
      // 4. 执行所有拦截器的 postHandle
      chain.applyPostHandle(request, response, mv);
      // 5. 处理返回结果(JSON 序列化、视图渲染等)
      processDispatchResult(request, response, chain, mv, exception);
      // 6. 触发拦截器的 afterCompletion(总是执行)
      chain.triggerAfterCompletion(request, response, exception);
      }

      五、HandlerExecutionChain —— Controller + 拦截器的组合体

      请求到达 DispatcherServlet 后,getHandler() 方法会将你的 Controller 方法和所有适用的拦截器打包成一个执行链。
      结构示意

      HandlerExecutionChain
      ├── Handler(你的 Controller 方法)
      ├── Interceptor A
      ├── Interceptor B
      └── Interceptor C

      执行顺序(链式调用,具有栈特性)

  • 进入时:A.pre → B.pre → C.pre → Controller
  • 返回时:C.post → B.post → A.post
  • 最终完成:C.after → B.after → A.after(即使前面出异常也会执行)

    六、@RequestScope 的底层原理 —— 代理对象,而非每次都 new

    很多人以为 @RequestScope 每次请求都会创建一个全新的 Bean,实际上 Spring 注入的是一个代理对象

特别提醒:
代理对象通过当前线程的 ThreadLocal 拿到绑定的请求上下文,从而找到属于当前请求的那个真实 @RequestScope 实例。
如果在 Controller 里用 @Async 等开了新线程,原请求的 ThreadLocal 会丢失,导致代理找不到请求上下文而直接报错。

@Autowired
private UserContext userContext;

实际注入的是 UserContext$$SpringProxy 代理类。该代理对象内部并不持有真实数据,当真正调用其方法时,它会从当前请求的 RequestAttributes 中动态获取属于当前请求的真实实例
流程

当前线程 → RequestAttributes → 真实的 UserContext

好处:即便 Controller 是单例(Singleton),也能安全地使用 @RequestScope 的 Bean,因为每次调用都会通过代理去获取当前请求对应的真实对象。

七、ThreadLocal 与 @RequestScope —— 如何安全地存放用户信息

在企业项目中,经常需要在任何地方(Service、DAO)获取当前登录用户,常用两种方案。

方案实现方式优点缺点最佳实践
ThreadLocalUserHolder.set(user) / UserHolder.get()极快,线程隔离必须手动 remove(),否则线程池复用时会内存泄漏或数据串人在拦截器的 afterCompletion 中清理
@RequestScope注解在 Spring 管理的 Bean 上Spring 自动管理生命周期,请求结束自动销毁,无泄漏风险性能比 ThreadLocal 多一点点反射/代理开销优先推荐,简单安全

推荐:存放用户上下文信息时,优先选择 @RequestScope。只有在对性能要求极高、并发极大的场景下,才考虑 ThreadLocal,并确保在拦截器的 afterCompletion 中执行 remove()

八、Controller 参数解析过程 —— 为什么参数能自动绑定

你写的 public Result get(Long id),Spring 能自动从请求里拿到 id,靠的是 HandlerMethodArgumentResolver 接口。
该解析器会遍历判断当前参数是否能被自己解析,若能则从 request 中取值并绑定。

常见注解与对应解析器

注解解析器
@RequestParamRequestParamMethodArgumentResolver
@PathVariablePathVariableMethodArgumentResolver
@RequestBodyRequestResponseBodyMethodProcessor
@RequestHeaderRequestHeaderMethodArgumentResolver

例如:@RequestHeader("token") String token 背后就是 RequestHeaderMethodArgumentResolver 在干活。

你也可以实现该接口并注册,来支持自定义的参数注入(比如自动注入当前登录用户对象)。

九、JSON 如何变成 Java 对象 —— HttpMessageConverter

前端发送 JSON:

POST
{ "name":"Tom" }

到后端自动变成 UserDTO 对象,核心组件是 HttpMessageConverter
默认使用的实现是 MappingJackson2HttpMessageConverter,底层依赖 Jackson
请求方向

请求体 JSON → Jackson 反序列化 → Java 对象 → Controller 参数

响应方向

Controller 返回的 Java 对象 → Jackson 序列化 → JSON 字符串 → HTTP 响应

因此 Jackson 是 Spring Boot 中处理 JSON 的事实标准,排查问题时经常要关注它。

十、统一异常处理 —— 别再到处 try-catch

在企业项目中,应使用 @RestControllerAdvice 进行全局异常拦截,避免在每个 Controller 方法中写重复的 try-catch

@RestControllerAdvice
public class GlobalExceptionHandler {
    @ExceptionHandler(Exception.class)
    public Result handleException(Exception e) {
        log.error("系统异常", e);
        return Result.fail(e.getMessage());
    }
    @ExceptionHandler(BusinessException.class)
    public Result handleBusinessException(BusinessException e) {
        return Result.fail(e.getCode(), e.getMessage());
    }
}

执行流程

Controller 抛出异常
      ↓
HandlerExceptionResolver 捕获
      ↓
找到匹配的 @ExceptionHandler 方法
      ↓
返回统一的错误响应

这样 Controller 只需关注正常业务逻辑,所有异常都会流入全局处理器,返回规范的接口格式。

十一、完整认证流程 —— 不要只相信 Token

真正的安全认证绝不能只解析 token,而必须结合 Redis 等存储做二次校验。
标准流程

1. 请求携带 JWT token
2. Interceptor 解析 token 得到 userId
3. 去 Redis 查询该 userId 对应的完整用户信息(含权限、状态)
4. 如果 Redis 中不存在或 token 已失效 → 直接返回 401
5. 将用户信息放入 UserContext(@RequestScope 管理的 Bean)
6. Controller 直接从 UserContext 获取用户信息,无需再解析 token

为什么要加 Redis?

  • Token 可能被伪造(弱签名或密钥泄露)
  • 用户可能已被管理员禁用,但 token 还未过期
  • 用户执行了“退出登录”,token 理应立刻失效

    总结:Token 只负责提供身份标识(userId),真正的用户资料和权限应从 Redis(或数据库)获取,并在请求上下文中传递。

    十二、Spring MVC 八大核心组件(高级理解)

    DispatcherServlet 只是总控,真正复杂的工作由这些组件完成:

    组件作用重要性
    HandlerMapping根据请求 URL 找到对应的 Handler(Controller 方法)★★★
    HandlerAdapter真正执行 Handler,适配不同类型的处理器★★★
    HandlerExceptionResolver处理异常,分发给 @ExceptionHandler 或 @ControllerAdvice★★★
    ViewResolver解析视图名,找到具体视图(前后端分离时用得少)
    MultipartResolver处理文件上传请求
    LocaleResolver国际化,解析客户端的语言/地区
    ThemeResolver主题切换(老旧项目中常见)
    FlashMapManager用于重定向时保存临时数据

其中最核心的三个:HandlerMapping、HandlerAdapter、HandlerExceptionResolver,理解它们才能真正把握 Spring MVC 的执行原理。


总结 —— 一条线全部串起来

完整请求处理链路:

Tomcat
  → Filter(登录校验、XSS、日志、跨域)
  → DispatcherServlet
  → HandlerMapping(找到 Controller 方法)
  → HandlerInterceptor.preHandle(权限、用户注入)
  → HandlerAdapter(执行方法)
  → Controller
  → Service
  → DAO / JdbcTemplate
  → MySQL
  → (若有异常)HandlerExceptionResolver → @RestControllerAdvice 统一处理
  → HttpMessageConverter(Java 对象 ↔ JSON)
  → HandlerInterceptor.postHandle / afterCompletion
  → 返回 Response

日常企业开发(SpringBoot 2.7 + JdbcTemplate + MySQL + Redis + JWT)中最核心的10个知识点:

  1. Filter — 容器层拦截,适合安全校验、跨域、日志
  2. Interceptor — Spring MVC 拦截,适合用户注入、权限、统计
  3. @RequestScope — 请求作用域 Bean,底层用代理实现
  4. ThreadLocal — 线程隔离的上下文存储,需手动清理
  5. HandlerMethodArgumentResolver — 参数解析器,实现自动注入
  6. HttpMessageConverter — JSON / 对象互转,底层 Jackson
  7. @RestControllerAdvice — 全局异常处理,不要到处 try-catch
  8. DispatcherServlet — 前端总控制器,调度所有请求
  9. HandlerExecutionChain — 拦截器与 Controller 的打包执行链
  10. Spring MVC 九大组件 — 理解项目架构离不开这些支撑组件
1

评论

博主关闭了所有页面的评论