定位:第 01 篇,讲透 mvc 设计模式、各核心组件职责、一次请求的完整处理链路与 dispatcherservlet 装配
适用版本:spring framework 6.x(jdk 17+)
一、mvc 模式
1.1 三角色
| 角色 | 职责 | 在 spring mvc 中 |
|---|---|---|
| model | 数据与业务状态 | 方法返回的数据/model 对象 |
| view | 呈现 | 模板(thymeleaf)或 json(rest) |
| controller | 接收请求、编排、返回 | @controller/@restcontroller 方法 |
1.2 价值
职责分离:请求入口(controller)与业务、呈现解耦;视图可替换(同一数据渲染 html 或 json);controller 薄、逻辑下沉到 service,便于测试。
浏览器/客户端 → controller(编排) → service(业务) → model
↓
view/json 呈现二、核心组件
理解这六个组件就理解了 spring mvc:
| 组件 | 职责 | 可定制 |
|---|---|---|
| dispatcherservlet | 前端控制器,所有请求统一入口 | 可多个、可换映射 |
| handlermapping | url → handler(找到处理方法) | 可加自定义 |
| handleradapter | 适配并调用 handler(解析注解、参数) | 主要用 requestmappinghandleradapter |
| handler | 你的 @requestmapping 方法 | 业务代码 |
| viewresolver | 视图名 → view(传统 mvc) | rest 场景不用 |
| httpmessageconverter | 对象 ↔ 请求/响应报文 | json/xml 转换器 |
前端控制器模式:所有请求经 dispatcherservlet 统一分发,避免每个资源各自处理入口逻辑——这是 mvc 框架的通用骨架。
三、请求处理链路
一次请求的完整流程(面试必背):
① 请求到达 dispatcherservlet
│
② handlermapping 匹配:根据 url 找到 handler(处理方法)+ 拦截器链
│
③ handleradapter 准备调用:解析方法参数(@requestparam/@requestbody 等,见 02 篇)
│
④ 执行 handler(你的业务方法)
│
⑤ 处理返回值:
├── 传统:返回视图名 → viewresolver 解析 → view 渲染
└── rest:@responsebody → httpmessageconverter 序列化为 json
│
⑥ 响应写回客户端
│
异常:任意环节抛异常 → handlerexceptionresolver 处理(见 04 篇)关键认知:
- handler 是方法不是类:handlermapping 定位到具体的 @requestmapping 方法;
- rest 与传统共用同一链路,差异只在第⑤步(消息转换 vs 视图渲染);
- 拦截器在②③之间执行(04 篇展开)。
四、dispatcherservlet 装配
4.1 boot 下的自动装配
webmvcautoconfiguration 自动注册 dispatcherservlet,映射到 /,并装配默认的 handlermapping、handleradapter、消息转换器。
4.2 上下文结构
dispatcherservlet 持有一个 webapplicationcontext(servlet 级),通常以根容器(root context,业务 bean)为父——子容器可见父容器 bean,反之不行。boot 中两者合一,这个分层在理解 xml 时代遗留项目时仍重要。
4.3 多 servlet 场景
默认一个 dispatcherservlet(/) 可注册多个,各自不同 url-pattern(如 /app/*、/admin/*) 每个有独立的 webapplicationcontext
五、总结
- mvc:model/view/controller 职责分离,controller 薄、逻辑下沉。
- 六大组件:dispatcherservlet 统一入口、handlermapping 找方法、handleradapter 解析调用、handler 业务方法、viewresolver/httpmessageconverter 处理输出。
- 请求链路:到达 → 映射 → 参数解析 → 执行 → 结果处理(视图或 json)→ 写回;异常交异常解析器。
- 装配:boot 自动注册映射 /;理解 web 上下文父子结构;多 servlet 各自独立上下文。
六、常见高频面试题
1. 描述一次请求在 spring mvc 中的完整处理流程。
要点:请求到达 dispatcherservlet → handlermapping 按 url 匹配到 handler(@requestmapping 方法)与拦截器链 → handleradapter 解析方法参数并调用 → handler 执行业务返回 → 处理返回值:传统走 viewresolver 渲染视图,rest(@responsebody)走 httpmessageconverter 序列化为 json → 写回响应。任意环节异常交 handlerexceptionresolver 处理。
2. dispatcherservlet 是什么?为什么叫前端控制器?
要点:它是 spring mvc 的统一请求入口,所有请求先到它,再由它分发给具体 handler——这是前端控制器(front controller)模式:集中处理入口逻辑(映射、参数解析、异常、视图),避免每个资源各自实现。好处是流程统一、横切能力(拦截、安全、日志)有统一挂载点。boot 自动装配它映射到 /。
3. handlermapping 和 handleradapter 的区别?
要点:handlermapping 负责"找"——根据请求(url/注解)定位到具体的 handler 及其拦截器链;handleradapter 负责"调"——适配并调用 handler,解析方法参数、处理返回值(@requestparam/@requestbody 等由它驱动)。常用实现:requestmappinghandlermapping(处理 @requestmapping)与 requestmappinghandleradapter。分离二者使框架可扩展不同的处理器风格。
4. @controller 和 @restcontroller 的区别?
要点:@restcontroller = @controller + @responsebody。@controller 的方法默认返回视图名(交给 viewresolver 渲染);@restcontroller 的方法返回值直接经 httpmessageconverter 序列化为响应体(通常 json),用于 rest api。需要"部分方法返回视图、部分返回 json"时用 @controller + 局部 @responsebody。
5. httpmessageconverter 的作用?常见有哪些?
要点:负责对象与 http 报文之间的双向转换——把请求体反序列化为方法参数(@requestbody),把返回值序列化为响应体(@responsebody)。常见:mappingjackson2httpmessageconverter(json)、stringhttpmessageconverter(字符串)、formhttpmessageconverter(表单)、xml 转换器等。内容协商(accept/content-type)决定选哪个转换器。
6. 什么是内容协商?
要点:根据请求与响应头协商数据格式。请求侧:content-type 声明请求体格式(决定反序列化用哪个转换器);响应侧:accept 声明客户端期望格式,服务端结合可用的 httpmessageconverter 与扩展名/参数决定返回 json 还是 xml 等。boot 默认以 json 为主。这让同一接口可服务不同格式的客户端。
7. rest 风格和传统 mvc 在链路上的差异在哪?
要点:前四步完全一致(映射、参数解析、执行)。差异在返回值处理:传统返回视图名,经 viewresolver 解析成 view 再渲染模型数据;rest 用 @responsebody(或 @restcontroller),返回值直接经 httpmessageconverter 序列化为报文写回。所以 rest 是 mvc 链路的一种输出形态,不是另一套框架。
8. spring mvc 的父子容器是怎么回事?
要点:传统结构有根容器(root,service/dao 等业务 bean)与 dispatcherservlet 的 web 子容器(controller 等 web bean);子可见父、父不可见子,避免 web 层污染业务层。boot 中合并为单一容器,不再区分。理解它有助于维护老的 xml 项目和解释某些 bean 可见性问题。
9. 如何自定义 handlermapping 或加多个?
要点:实现 handlermapping 接口并注册为 bean,dispatcherservlet 启动时收集所有 handlermapping 按 order 排序,请求到来时依次尝试直到匹配。可用于自定义路由规则(如基于版本头的路由)。常见扩展点还包括自定义 handleradapter、handlerinterceptor。不过多数场景用 @requestmapping 注解驱动即可,无需自定义。
10. 为什么 spring mvc 是同步阻塞模型?有什么影响?
要点:基于 servlet 规范,默认每个请求占用一个线程从入口到响应结束(阻塞式处理,含等待下游/db 的时间)。影响:高并发下线程数成为吞吐瓶颈,线程被 io 等待占用而非干活。对策:扩大线程池(治标)、异步方法释放线程(部分缓解)、或换响应式栈(webflux,06 篇)与异步 servlet。虚拟线程(jdk 21)也在改变这一模型的代价。
到此这篇关于spring mvc 架构与请求处理全链路解析:从 dispatcherservlet 到响应返回的文章就介绍到这了,更多相关spring mvc架构与请求内容请搜索代码网以前的文章或继续浏览下面的相关文章希望大家以后多多支持代码网!
发表评论