m0_63990694头像

SpringMVC 底层原理:DispatcherServlet、九大组件、请求全流程、参数绑定、消息转换器

前面 4 篇我们讲解了 Spring IOC、AOP、SpringBoot 自动配置、Spring 事务。本篇作为 Spring 全家桶系列收尾,讲解 SpringMVC,也就是 Spring 体系的 Web 层框架。 SpringBoot 的 Web 能力底层就是 SpringMVC,日常写@RestController、@RequestMapping接口,都是 SpringMVC 的能力。很多开发只会写 Controller 接口,但是不清楚一次 HTTP 请求从浏览器到后端,再返回响应,完整经历了哪些组件;不理解参数解析、JSON 序列化、拦截器、全局异常处理器底层原理。本文从 MVC 设计思想、DispatcherServlet、九大组件、完整请求流程、参数绑定、HttpMessageConverter、拦截器、开发踩坑完整拆解。

前言

MVC 是经典分层架构:Model(模型数据)、View(视图)、Controller(控制器)。 传统 Servlet 开发:每个请求对应一个 Servlet,大量重复代码,手动解析 request 参数、封装 response,耦合严重,维护困难。

SpringMVC 基于前端控制器(Front Controller)模式,所有请求统一交给DispatcherServlet接收,由 DispatcherServlet 调度各个可插拔组件完成请求处理。

SpringMVC 构建在 Servlet 规范之上,同时依托 Spring IOC 容器,Controller、拦截器、异常处理器全部作为 Bean 托管。 SpringBoot 内置 SpringMVC,自动装配 DispatcherServlet,不需要 web.xml 配置。

一、核心:DispatcherServlet(前端控制器)

DispatcherServlet是整个 SpringMVC 的入口,本质是一个 Servlet。 职责:

  1. 拦截全部 HTTP 请求;
  2. 协调九大组件,调度请求处理链路;
  3. 捕获处理过程中的异常,交给异常解析器;
  4. 最终渲染视图 / 写出响应返回客户端。

核心设计思想:单一职责 + 可插拔组件。DispatcherServlet 只做调度,具体工作交给 HandlerMapping、HandlerAdapter 等组件完成,组件可以自定义替换、扩展。

二、SpringMVC 九大核心组件

全部由 Spring IOC 管理,DispatcherServlet 启动时自动加载这些 Bean。

  1. HandlerMapping 处理器映射器 根据请求 URL、请求方式(GET/POST)、请求头,查找匹配的 Handler(标注 @RequestMapping 的 Controller 方法,叫 HandlerMethod),同时把匹配的拦截器一起封装返回。

常用实现:RequestMappingHandlerMapping,处理@RequestMapping注解。

  1. HandlerAdapter 处理器适配器 DispatcherServlet 不直接调用 Handler,通过适配器模式执行 Handler。 不同类型 Handler 有不同执行方式,适配器屏蔽差异。最常用RequestMappingHandlerAdapter,负责执行注解 Controller 方法,内部包含参数解析器、返回值处理器。
  2. HandlerExceptionResolver 异常解析器 Controller、拦截器执行抛出异常时,由异常解析器捕获,处理异常,封装返回结果。我们开发的全局异常处理器就是实现这个接口。
  3. ViewResolver 视图解析器 把逻辑视图名称(如"user/list")解析为 View 视图对象。前后端分离项目用@RestController直接返回 JSON,不会走视图渲染。

如 ThymeleafViewResolver、InternalResourceViewResolver(JSP)。

  1. View 视图 负责渲染模型数据,生成 HTML 页面。前后端分离项目基本不用。
  2. MultipartResolver 文件上传解析器 解析 multipart/form-data 类型请求,封装文件上传对象。
  3. LocaleResolver 国际化解析器 解析请求对应的区域语言(zh-CN、en-US),用于国际化页面。
  4. ThemeResolver 主题解析器 页面主题样式解析,现在很少使用。
  5. FlashMapManager 闪存管理器 重定向时传递临时参数,避免参数放在 URL 上。

重点记忆:日常开发最核心 4 个组件:DispatcherServlet、HandlerMapping、HandlerAdapter、HandlerExceptionResolver。

三、一次 HTTP 请求完整执行流程(核心)

浏览器发起 HTTP 请求 → Tomcat 接收请求 → 交给 DispatcherServlet

阶段 1:HandlerMapping 查找处理器

DispatcherServlet 遍历所有 HandlerMapping,根据 URL、请求方法 匹配,找到对应的 HandlerMethod,同时组装匹配的拦截器链 HandlerExecutionChain。

找不到匹配 Handler,直接返回 404。

阶段 2:执行拦截器 preHandle ()

按顺序执行拦截器的 preHandle()

任意一个 preHandle 返回 false:直接终止请求,返回响应,不会执行 Controller。

阶段 3:寻找 HandlerAdapter

DispatcherServlet 查找能够支持当前 HandlerMethod 的适配器,常用:RequestMappingHandlerAdapter。

阶段 4:参数绑定与解析(参数解析器 ArgumentResolver)

HandlerAdapter 调用参数解析器,从 HttpServletRequest 解析各类参数:

  • URL 路径变量:@PathVariable
  • URL 查询参数 / 表单参数:@RequestParam
  • 请求体 JSON:@RequestBody(依赖 HttpMessageConverter)
  • Header、Cookie、实体对象

解析完成后,自动做类型转换、JSR303 参数校验,组装成 Controller 方法入参。

阶段 5:执行 Controller 业务方法

调用 Controller 方法,执行业务代码,拿到方法返回值。

阶段 6:返回值处理器处理返回结果

HandlerAdapter 使用返回值处理器对返回值做处理:

  • 标记 @ResponseBody:通过 HttpMessageConverter 将对象序列化为 JSON,写入 response body;
  • 普通字符串返回:视为逻辑视图名称,进入视图渲染流程。
阶段 7:执行拦截器 postHandle ()

Controller 方法正常执行完毕后、视图渲染之前执行 postHandle。

如果 Controller 抛出异常,postHandle 不会执行。

阶段 8:视图渲染(前后端分离项目直接跳过)

如果返回 ModelAndView / 视图名称:ViewResolver 解析视图,View 渲染页面。

阶段 9:执行拦截器 afterCompletion ()

视图渲染完成后执行。

无论 Controller 正常执行还是抛出异常,都会执行,适合写资源释放逻辑。

阶段 10:异常兜底处理

整个链路任意环节抛出异常,都会交给 HandlerExceptionResolver 统一捕获,封装错误响应。

一句话精简流程: 请求→DispatcherServlet→HandlerMapping 找 Handler→拦截器 preHandle→HandlerAdapter→参数解析→调用 Controller→处理返回值→postHandle→视图渲染→afterCompletion→返回响应。

四、关键模块详解

4.1 HttpMessageConverter 消息转换器

作用:负责请求体序列化、响应体反序列化。

  • 读请求:把 Request Body 的 JSON 字符串转为 Java 对象(@RequestBody);
  • 写响应:把 Java 对象序列化为 JSON 字符串写入 Response(@ResponseBody)。

SpringBoot 默认配置MappingJackson2HttpMessageConverter,底层 Jackson。

坑点:@RequestBody只能读取 POST 请求 body,不能读取 url 参数;Content-Type 必须是 application/json。

4.2 拦截器 HandlerInterceptor

三个方法:

  1. preHandle:Controller 执行之前;返回 true 放行,false 拦截。适合登录校验、token 校验。
  2. postHandle:Controller 执行成功,视图渲染之前;可以修改 Model 数据。异常不会执行。
  3. afterCompletion:请求全部完成,视图渲染完毕;无论是否异常都会执行,资源清理。

拦截器和过滤器 Filter 区别

  • Filter:Servlet 规范,属于 Tomcat,在 DispatcherServlet之前执行;只能拿到 request、response;
  • HandlerInterceptor:SpringMVC 组件,在 DispatcherServlet 内部,Controller 前后执行;可以拿到 HandlerMethod 对象,Spring Bean。

4.3 @Controller 和 @RestController

@Target(ElementType.TYPE)
@RestController = @Controller + @ResponseBody
  • @Controller:返回视图页面;
  • @RestController:类上自带@ResponseBody,所有方法返回值直接写入响应体,不走视图解析。

五、常用注解原理

  1. @RequestMapping:派生注解@GetMapping/@PostMapping,在容器启动阶段,被RequestMappingHandlerMapping扫描,把 URL 和 HandlerMethod 存入映射注册表。
  2. @RequestParam:解析 url 查询参数、表单参数。
  3. @PathVariable:解析 URL 路径占位符。
  4. @RequestBody:使用消息转换器读取请求体 JSON。
  5. @RequestHeader:读取请求头。

六、开发实战踩坑清单

  1. GET 请求不能使用 @RequestBody GET 没有请求体,@RequestBody读取 body 会报错;GET 参数用@RequestParam、@PathVariable。
  2. 拦截器 preHandle 返回 false,afterCompletion 仍然会执行;但是 postHandle 不会执行。
  3. 全局异常处理器只能捕获 Controller 内抛出的异常;Filter 中抛出的异常,SpringMVC 异常解析器捕获不到。
  4. 参数绑定类型转换失败、JSR303 校验失败,会抛出 MethodArgumentNotValidException,交给全局异常处理器。
  5. @ResponseBody依赖 HttpMessageConverter,如果没有 Jackson 依赖,JSON 序列化失败。
  6. 静态资源(html、图片)默认不走 Controller,DispatcherServlet 放行静态资源。
  7. 跨域问题:浏览器同源策略。可以使用@CrossOrigin注解,或者 WebMvcConfigurer 统一配置跨域。
@Configuration
public class WebConfig implements WebMvcConfigurer {
    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**")
                .allowedOrigins("http://localhost:8080")
                .allowedMethods("GET","POST");
    }
}

注意:allowCredentials=true 时,allowedOrigins 不能写*,会冲突。

WebMvcConfigurer 不要加@EnableWebMvc;加上之后 SpringBoot 自动配置失效,全部 MVC 配置需要自己手动配置。

七、SpringMVC 和 SpringBoot 的关系

SpringBoot Web Starter 自动装配 SpringMVC: 自动创建 DispatcherServlet、自动装配 HandlerMapping、HandlerAdapter、消息转换器、视图解析器等组件。

如果不使用 SpringBoot,SSM 项目需要在 xml 手动注册 DispatcherServlet 和 MVC 组件。

八、问答汇总

Q1:SpringMVC 的执行流程?

A:浏览器请求到达 DispatcherServlet,HandlerMapping 匹配 url 找到 Handler 和拦截器链;执行拦截器 preHandle;HandlerAdapter 解析请求参数,调用 Controller 方法;返回值处理器处理结果;执行 postHandle;视图渲染;执行 afterCompletion;异常交给异常解析器处理。

Q2:Filter 和 Interceptor 的区别?

A:Filter 属于 Servlet 规范,Tomcat 执行,在 DispatcherServlet 之前;Interceptor 是 SpringMVC 组件,在 DispatcherServlet 内部,Controller 前后执行。Filter 只能操作 request、response;Interceptor 可以拿到 HandlerMethod,依赖 Spring 容器。

Q3:HttpMessageConverter 作用?

A:消息转换器,负责请求体 JSON 转 Java 对象(@RequestBody),Java 对象序列化为 JSON 写入响应(@ResponseBody)。SpringBoot 默认使用 Jackson。

Q4:九大组件简单说几个?

A:DispatcherServlet 调度,HandlerMapping 映射处理器,HandlerAdapter 执行处理器,HandlerExceptionResolver 异常处理,ViewResolver 视图解析器,MultipartResolver 文件上传解析器。

Q5:@RestController 是什么?

A:@Controller + @ResponseBody,类上所有方法返回值直接写入 response body,不进行视图解析,前后端分离开发常用。

Q6:preHandle、postHandle、afterCompletion 执行顺序和异常场景?

A:正常流程:preHandle → Controller → postHandle → afterCompletion。 Controller 抛出异常:preHandle 执行,postHandle 不执行,afterCompletion 依然执行。preHandle 返回 false 直接终止,afterCompletion 执行。

Q7:@EnableWebMvc 作用?

A:开启 SpringMVC 完全手动配置,会覆盖 SpringBoot 的 Web 自动配置,消息转换器、静态资源等自动配置失效,一般业务项目不要加。

结语

SpringMVC 是 Spring 全家桶 Web 层的核心,和前面 IOC、AOP 一脉相承。DispatcherServlet 本身是 IOC 容器中的 Bean,Handler、拦截器、异常处理器全部托管在 IOC;AOP 可以作用在 Controller、Service 方法上。 理解 SpringMVC,你就能打通从 HTTP 请求 → Web 层 → Service 层 → 数据库的完整链路。 至此,Spring 全家桶系列 5 篇博客全部完成:

  1. Spring IOC 容器原理
  2. Spring AOP 原理
  3. SpringBoot 自动配置 + 自定义 Starter
  4. Spring 事务(声明式 & 编程式)
  5. SpringMVC 原理

转载自 CSDN-专业IT技术社区

原文链接:https://blog.csdn.net/m0_63990694/article/details/167704848

文章来源转载

评论

评论列表

微信小程序
QQ小程序

关于作者

点赞数:0
关注数:0
粉丝:0
文章:0
关注标签:0
加入于:--