Spring MVC 全流程深度解析:从请求到响应的暗中流程

前言

在 Java Web 开发的世界里,其底层处理 HTTP 请求的核心机制依然 Spring MVC。

很多初学者会觉得 Spring MVC 像一个黑盒:我们在浏览器输入 URL,敲下回车,屏幕上就出现了数据。这中间到底发生了什么?

今天,我们就拆开这个黑盒,用通俗易懂的方式,带你走完一次 HTTP 请求。


一、 核心架构:一种“分工明确”的设计

Spring MVC 的设计灵感来源于经典的 MVC (Model-View-Controller) 设计模式,但它通过引入一个“中央调度器”,将职责划分得更加极致。

我们可以将其想象成一家米其林餐厅的运作流程:

  1. DispatcherServlet(前台经理/调度员)

    • 核心角色。它是整个框架的“心脏”。所有请求必须先经过它,由它负责分发任务,它自己不干活,只负责指挥。

  2. HandlerMapping(点餐员/菜单)

    • 负责根据 URL 找到对应的处理器(Controller)。它知道“哪位厨师负责做这道菜”。

  3. HandlerAdapter(厨房调度/适配器)

    • 负责执行处理器(Controller)。因为 Controller 的写法千变万化,适配器负责屏蔽差异,统一调用。

  4. Controller(大厨)

    • 开发者最熟悉的组件。负责接收参数、调用业务逻辑(Service)、返回数据。

  5. ViewResolver(摆盘师/视图解析器)

    • 负责将数据(Model)和页面模板(View)结合,渲染出最终的 HTML。


二、 七步走:请求的生命周期

当一个 HTTP 请求到达服务器时,它会经历以下 7 个关键步骤:

1. 拦截请求 (The Interception)

用户在浏览器发起请求(如 GET /user/profile)。这个请求首先会被部署在 Tomcat 中的 DispatcherServlet 捕获。

注意:在 Spring Boot 中,DispatcherServlet 会自动配置并映射到 /,即拦截所有请求。

2. 查找处理器 (Lookup)

DispatcherServlet 此时并不知道这个 URL 该由谁处理。它会查询 HandlerMapping

  • HandlerMapping 会扫描所有的 @RequestMapping 注解,建立 URL 到 Controller 方法的映射关系。

  • 结果:返回一个 执行链 (Execution Chain),其中包含具体的 Controller 对象和可能存在的拦截器 (Interceptors)

3. 请求适配 (Adaptation)

拿到了 Controller,但 DispatcherServlet 不会直接调用它(因为 Controller 可能有多种实现方式)。它会把任务交给 HandlerAdapter

  • HandlerAdapter 的作用就是“翻译”,通过反射机制调用具体的 Controller 方法。

4. 业务处理 (Execution) —— 核心步骤

此时,终于轮到我们写的代码登场了。Controller 开始工作:

  • 接收参数(自动封装 Form 表单或 JSON)。

  • 调用 Service 层进行业务逻辑处理(如查数据库)。

  • 结果:Controller 执行完毕,通常会返回两个东西:

    • Model:处理后的数据。

    • View:数据的展示方式(逻辑视图名)。

    • (注:如果是前后端分离项目,这里会发生变化,详见下文)

5. 视图解析 (View Resolution)

DispatcherServlet 拿到了 ModelAndView,但它还是看不懂 "success" 或 "user_detail" 到底是什么。它会求助于 ViewResolver

  • ViewResolver 会根据配置(如 prefix="/WEB-INF/", suffix=".jsp"),找到真正的物理视图文件。

6. 视图渲染 (Rendering)

通过视图解析器,Model 中的数据被填充到 View 模板中(JSP, Thymeleaf, Freemarker)。

  • 这一步生成了最终用户能看到的 HTML 代码

7. 响应用户 (Response)

最后,DispatcherServlet 将渲染好的 HTML(或数据)通过 HTTP 响应流返回给浏览器。用户看到了页面。


三、 现代化的变迁:前后端分离与 RESTful

在现代开发(尤其是 React/Vue + Spring Boot)中,上述流程的第 5、6 步通常会被省略。

为什么? 因为我们不再由后端生成 HTML,而是直接返回 JSON 数据

关键差异点:

  • 注解变化:我们使用 @RestController(等同于 @Controller + @ResponseBody)。

  • 组件介入HttpMessageConverter 替代了 ViewResolver

    • 当 HandlerAdapter 检测到 @ResponseBody 注解时,它不会去走视图解析的流程,而是直接利用消息转换器(如 Jackson),将 Java 对象序列化为 JSON 字符串。

  • 流程简化

    Request -> DispatcherServlet -> HandlerMapping -> HandlerAdapter -> Controller -> JSON -> Response


四、 源码级的小细节(面试加分项)

  1. 单例问题: Spring 中的 Controller 默认是单例 (Singleton) 的。这意味着多个线程会同时访问同一个 Controller 实例。

    • 警示:千万不要在 Controller 里定义成员变量(比如 private int count)来存储请求状态,否则会引发严重的线程安全问题!

  2. 拦截器 (Interceptor) vs 过滤器 (Filter)

    • Filter:属于 Servlet 规范,工作在 DispatcherServlet 之前。

    • Interceptor:属于 Spring 框架,工作在 DispatcherServlet 内部(第 2 步和第 3 步之间)。它可以精确地控制对某个具体的 Controller 方法进行拦截。


结语

Spring MVC 的强大之处在于其高度的解耦。通过将请求处理拆解为一个个独立的组件,开发者可以专注于业务逻辑(Controller),而无需操心 HTTP 协议的解析、视图的渲染等底层细节。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值