时间:2026年4月9日
系列:Spring全家桶原理精讲 · 第3期
读者:技术入门/进阶学习者 · 在校学生 · 面试备考者 · Java工程师
定位:技术科普 + 原理讲解 + 代码示例 + 面试要点
开篇

在Java Web开发的世界里,Spring MVC几乎是绕不开的核心技术。无论是初入行的开发者,还是经验丰富的老兵,每天都会与它打交道。经纬AI助手梳理技术栈时发现一个普遍现象:很多人会用@Controller和@RequestMapping写接口,但一旦遇到参数绑定异常、拦截器不生效、请求乱码等问题,往往无从下手——根源在于只记住了“怎么用”,却没搞懂“发生了什么”。本文将从一次HTTP请求的入口开始,逐环节拆解Spring MVC的执行流程,包含原理图解、代码示例和面试高频题,帮你彻底吃透这个Java Web开发的中枢框架。
一、为什么需要Spring MVC:从混沌到秩序

传统方式的痛点
在Spring MVC诞生之前,Java Web开发经历了一段“混沌期”。早期的JSP Model 1时代,URL直接映射到物理文件(如/login.jsp或/user.cgi),每个页面文件都混杂着参数解析、业务调用和HTML拼接,这种架构被称为“意大利面条式代码”——当需要修改通用逻辑(如全站增加CSRF防护)时,可能涉及成百上千个文件的改动-2。
后来出现了Servlet + JSP的Model 2架构(即MVC雏形),有了分层思想。但问题依然存在:如果在一个项目中配置了100个Servlet来处理不同URL,这100个Servlet中依然存在大量重复代码——编码设置、参数获取、异常捕获、视图跳转……代码冗余度极高,维护成本居高不下-2。
前端控制器模式的登场
Spring MVC的核心设计模式是前端控制器(Front Controller) ,即用一个中央Servlet统一接收所有请求,再分发给具体的处理器-2。这个中央调度器就是DispatcherServlet,它彻底解决了Controller层代码重复的问题,将Web开发从“各自为政”带入了“统一调度”的工业化时代。
二、核心组件讲解
DispatcherServlet(前端控制器)
DispatcherServlet是Spring MVC的核心,继承自HttpServlet,相当于请求处理的“中央调度器”,统一接收所有HTTP请求,协调其他组件完成处理流程-1。在Spring Boot项目中,它被自动配置,默认拦截除静态资源外的所有请求。
HandlerMapping(处理器映射器)
HandlerMapping负责根据请求的URL和HTTP方法,找到对应的处理器(即@Controller中的方法)以及关联的拦截器,返回HandlerExecutionChain(处理器执行链)-1。
通俗类比:DispatcherServlet是餐厅的前台经理,HandlerMapping是点餐系统的菜品目录——经理收到顾客的点单,先查目录找到这道菜该由哪个厨师做。
HandlerAdapter(处理器适配器)
HandlerAdapter解决了一个核心问题:DispatcherServlet如何统一调用不同类型的处理器?它充当适配器角色,适配注解式Controller、传统Controller接口等不同处理器类型,调用Handler的业务方法-1。
三大组件的协作关系
| 组件 | 作用 | 类比 |
|---|---|---|
DispatcherServlet | 统一调度 | 前台经理 |
HandlerMapping | 查找处理器 | 点餐目录 |
HandlerAdapter | 执行处理器 | 厨师调度员 |
ViewResolver(视图解析器)
ViewResolver将ModelAndView中的逻辑视图名称解析为具体的View实例(如JSP、Thymeleaf视图),完成页面渲染-1。
HandlerInterceptor(处理器拦截器)
HandlerInterceptor类似AOP切面,可在处理器执行前后、视图渲染前后做增强处理,常用于登录校验、日志记录、性能监控等场景-1。
三、执行流程:从HTTP请求到响应的十步走
以一个简单的请求为例:用户访问/user/get?id=1。
步骤1:请求到达DispatcherServlet
HTTP请求到达Web服务器(如Tomcat),根据配置转发给DispatcherServlet。核心入口是doDispatch方法-1。
步骤2:调用HandlerMapping获取处理器
DispatcherServlet调用HandlerMapping,根据请求URL找到对应的HandlerMethod和拦截器,返回HandlerExecutionChain-3。
步骤3:获取HandlerAdapter
DispatcherServlet根据处理器类型,从容器中获取能执行该处理器的HandlerAdapter。注解式Controller对应RequestMappingHandlerAdapter-14。
步骤4:执行拦截器preHandle
在调用真正的业务方法之前,先执行拦截器链的preHandle方法。如果任一preHandle返回false,请求被拦截,流程终止-14。
步骤5:HandlerAdapter执行Controller方法
HandlerAdapter通过反射调用Controller方法。这个环节包含大量细节工作:参数解析器将请求参数绑定到方法参数(@RequestParam、@RequestBody等),返回值处理器处理返回结果(@ResponseBody转JSON等)-14。
步骤6:处理器返回ModelAndView
Controller方法执行完毕,返回ModelAndView对象(包含视图名称和模型数据)。对于REST接口,直接返回JSON数据,没有视图解析环节-3。
步骤7:执行拦截器postHandle
在视图渲染之前,执行拦截器链的postHandle方法,可以对ModelAndView进行额外处理-14。
步骤8:视图解析
DispatcherServlet将ModelAndView传给ViewResolver,解析出具体的View对象(如JSP、Thymeleaf模板)-3。
步骤9:视图渲染
View结合模型数据进行渲染,生成HTML内容返回给DispatcherServlet-3。
步骤10:拦截器afterCompletion与响应返回
执行拦截器链的afterCompletion方法(无论是否发生异常都会执行),最后将响应内容返回给客户端-3。
源码视角:doDispatch核心骨架
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) { // 1. 根据请求找到处理器执行链 HandlerExecutionChain mappedHandler = getHandler(request); // 2. 找到适配器 HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler()); // 3. 执行拦截器preHandle if (!mappedHandler.applyPreHandle(request, response)) { return; } // 4. 调用处理器业务方法 ModelAndView mv = ha.handle(request, response, mappedHandler.getHandler()); // 5. 执行拦截器postHandle mappedHandler.applyPostHandle(request, response, mv); // 6. 渲染视图 render(mv, request, response); // 7. 执行拦截器afterCompletion mappedHandler.triggerAfterCompletion(request, response, null); }
源码出处:org.springframework.web.servlet.DispatcherServletdoDispatch-14
四、代码示例:从传统到现代
传统方式(xml配置)
<!-- web.xml中配置多个Servlet,每个URL一个 --> <servlet> <servlet-name>userServlet</servlet-name> <servlet-class>com.example.UserServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>userServlet</servlet-name> <url-pattern>/user</url-pattern> </servlet-mapping> <!-- 如果新增100个接口,就需要配置100个Servlet -->
Spring MVC方式(注解驱动)
@RestController @RequestMapping("/user") public class UserController { @Autowired private UserService userService; @GetMapping("/get") public User getUser(@RequestParam Long id) { return userService.findById(id); } @PostMapping("/create") public User createUser(@RequestBody UserDto dto) { return userService.create(dto); } }
改进效果:一个UserController可以包含任意多个处理方法,配置从“按URL配置”简化为“按类+方法注解”,代码量大幅降低,可维护性显著提升。
五、底层原理:技术支撑点
1. 反射机制
HandlerAdapter通过Java反射调用Controller方法,这是实现“框架调用开发者代码”的核心基础-53。
2. 策略模式
Spring MVC在初始化DispatcherServlet时,加载九大核心策略接口:HandlerMapping、HandlerAdapter、ViewResolver、HandlerExceptionResolver等。如果没有找到自定义Bean,就从DispatcherServlet.properties中加载默认实现-2。
3. 父子容器(IoC容器级联)
Spring MVC存在两级IoC容器:父容器由ContextLoaderListener加载,包含Service、DAO等业务Bean;子容器由DispatcherServlet加载,包含Controller、ViewResolver等Web层Bean,子容器继承父容器的所有Bean-10。
实践提示:理解父子容器关系有助于排查“Controller无法注入Service”等常见问题——两个容器不在同一层级。
六、高频面试题与参考答案
面试题1:Spring MVC的核心组件有哪些?
参考答案(踩分点:组件清单 + 各自职责 + DispatcherServlet的核心地位):
DispatcherServlet:前端控制器,统一调度所有组件,是整个流程的中枢。
HandlerMapping:处理器映射器,根据URL找到对应的处理器和拦截器。
HandlerAdapter:处理器适配器,统一调用不同类型的处理器。
ViewResolver:视图解析器,将逻辑视图名解析为物理视图。
HandlerInterceptor:拦截器,在处理器执行前后做增强处理。
HandlerExceptionResolver:异常解析器,统一处理全局异常。
MultipartResolver:文件上传解析器。
面试题2:描述Spring MVC的完整执行流程。
参考答案(踩分点:十个步骤 + 关键组件 + 返回路径):
客户端发送HTTP请求到
DispatcherServlet。DispatcherServlet调用HandlerMapping查找处理器,返回HandlerExecutionChain。DispatcherServlet获取HandlerAdapter。执行拦截器的
preHandle方法。HandlerAdapter调用Controller业务方法。处理器返回
ModelAndView。执行拦截器的
postHandle方法。DispatcherServlet调用ViewResolver解析视图。视图渲染,生成响应内容。
执行拦截器的
afterCompletion方法,返回响应给客户端。
面试题3:@Controller和@RestController的区别?
参考答案(踩分点:@RestController = @Controller + @ResponseBody + 使用场景):
@Controller:标识类为Spring MVC控制器,方法返回值默认是视图名称,需要配合ViewResolver渲染页面;如需返回JSON,必须在方法上加@ResponseBody。@RestController:@Controller和@ResponseBody的组合注解,类中所有方法都隐式添加@ResponseBody,返回值直接作为HTTP响应体(JSON/XML),适用于纯REST API开发-50。
面试题4:HandlerMapping的工作原理?
参考答案(踩分点:启动时建立映射表 + 运行时查表):
初始化阶段:Spring MVC启动时,
RequestMappingHandlerMapping扫描所有@Controller类和@RequestMapping方法,将URL路径、HTTP方法等信息与HandlerMethod对象建立映射关系,存入内部的映射表。请求处理阶段:收到请求时,根据请求URL和HTTP方法查表,找到对应的
HandlerMethod和关联的拦截器,封装为HandlerExecutionChain返回-14。
面试题5:如何自定义拦截器?
参考答案(踩分点:实现HandlerInterceptor接口 + 注册配置):
实现
HandlerInterceptor接口,重写preHandle、postHandle、afterCompletion三个方法。在配置类(实现
WebMvcConfigurer)中重写addInterceptors方法,注册自定义拦截器并指定拦截路径。
七、总结
核心知识点回顾
| 知识点 | 一句话总结 |
|---|---|
| 前端控制器模式 | 用一个中央Servlet统一收口,调度所有组件 |
| DispatcherServlet | 九大策略组件的中枢调度器 |
| 执行流程 | 映射→适配→执行→解析→渲染,十步闭环 |
| 父子容器 | 父容器管Service,子容器管Controller |
重点提醒
doDispatch是核心入口:看懂这段源码,就理解了整个执行流程的骨架-14。
HandlerMapping vs HandlerAdapter:前者负责“找到”,后者负责“执行”,分工明确,缺一不可。
面试常见误区:很多人把
@RestController和@Controller混为一谈,或只记得执行流程的前三步,漏掉拦截器链和视图解析环节。
下篇预告
下一期我们将深入Spring MVC的源码层面,拆解RequestMappingHandlerAdapter中参数解析器和返回值处理器的底层实现机制,带你看懂@RequestParam和@RequestBody背后的反射奥秘,敬请期待!