news 2026/9/29 10:23:17

Spring MVC 前置必修:吃透 Servlet 底层,理解 MVC 设计由来

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Spring MVC 前置必修:吃透 Servlet 底层,理解 MVC 设计由来

1. 引言

很多初学者在接触 Spring MVC 时,往往只会复制粘贴代码:照着教程写一个@Controller、加一个@RequestMapping,请求就能通,但一旦遇到 404、参数绑定失败、拦截器不生效等问题就无从下手。究其原因,是缺少 Servlet 底层基础,不理解 Spring MVC 的设计由来。

本文的核心目标,就是补齐 Servlet 底层基础,让你理解 Spring MVC 为什么这样设计,避免后续学习只会复制粘贴代码。我们将用三天时间,从 Servlet 核心规范出发,逐步过渡到 MVC 架构模式,最终搭建起 Spring MVC 的基础开发环境,跑通第一个纯注解驱动的入门案例。

2. 学习路线总览

本阶段的学习分为三天,每天都有明确的目标与核心知识点:

  • Day1:吃透 Servlet 核心规范 —— 掌握 Servlet 生命周期、Tomcat 容器运行原理,手写原生 Servlet 实现简单请求处理,直观感受传统 Servlet 开发的代码冗余痛点
  • Day2:深入理解 MVC 架构模式 —— 理清 Model、View、Controller 三层的职责划分,对比三层架构与 MVC 的协作关系,掌握 MVC 架构解耦、易维护的核心优势
  • Day3:搭建 Spring MVC 基础开发环境 —— 导入核心 Maven 依赖,完成第一个纯注解驱动的 Spring MVC 入门案例,验证请求响应全链路通跑

整体路线遵循「先底层、后框架」的原则:先用手写 Servlet 感受传统开发的痛点,再理解 MVC 如何解决这些痛点,最后用 Spring MVC 验证全链路,从而真正理解框架的设计由来。

3. Day1:吃透 Servlet 核心规范

3.1 Servlet 生命周期

Servlet 的生命周期由容器(Tomcat)管理,主要分为三个阶段:

  • init:Servlet 被创建后调用一次,用于初始化资源,如加载配置、建立数据库连接
  • service:每次请求到来时调用,负责处理请求并生成响应,是核心业务逻辑的入口
  • destroy:应用卸载或容器关闭时调用一次,用于释放资源

理解生命周期,是理解容器如何管理组件的基础,也是后续理解 Spring 容器管理 Bean 生命周期的铺垫。

3.2 Tomcat 容器运行原理

Tomcat 作为 Servlet 容器,负责接收 HTTP 请求并分发到对应的 Servlet。其核心流程为:

  1. 客户端发起 HTTP 请求,Tomcat 的 Connector 监听端口并接收请求
  2. 请求被封装为HttpServletRequest与HttpServletResponse对象
  3. Tomcat 根据 URL 映射找到对应的 Servlet,调用其service方法
  4. Servlet 处理完业务后,将结果写入响应对象,Tomcat 将其返回给客户端

理解这一流程,就能明白请求是如何被容器接收并分发的,这也是 Spring MVC 中DispatcherServlet的前身。

3.3 手写原生 Servlet:感受代码冗余痛点

下面手写一个原生 Servlet,实现简单的请求处理:

@WebServlet("/hello")publicclassHelloServletextendsHttpServlet{@OverrideprotectedvoiddoGet(HttpServletRequestreq,HttpServletResponseresp)throwsServletException,IOException{// 手动处理请求参数Stringname=req.getParameter("name");if(name==null){name="World";}// 手动拼接 HTML 响应resp.setContentType("text/html;charset=UTF-8");PrintWriterout=resp.getWriter();out.println("<html><body>");out.println("<h1>Hello, "+name+"!</h1>");out.println("</body></html>");}}

这段代码虽然能跑通,但暴露了传统 Servlet 开发的几个痛点:

  • 参数绑定繁琐:每次都要手动调用getParameter并做类型转换
  • 响应拼接原始:HTML 需要手动拼接字符串,难以维护
  • 逻辑耦合严重:请求处理、业务逻辑、视图渲染全部堆在一个方法里
  • 配置分散:URL 映射、初始化参数等散落在注解与配置文件中

正是这些痛点,催生了 MVC 架构模式与 Spring MVC 框架。

4. Day2:深入理解 MVC 架构模式

4.1 Model、View、Controller 三层职责划分

MVC 将应用程序划分为三个核心部分:

  • Model(模型):负责业务逻辑与数据访问,封装数据与状态,不关心如何展示
  • View(视图):负责展示数据,将 Model 中的数据渲染给用户,如 JSP、Thymeleaf 模板
  • Controller(控制器):负责接收请求、调用 Model 处理业务、选择 View 渲染结果,是请求的调度中枢

三层各司其职,通过明确的接口协作,从而降低耦合、提升可维护性。

4.2 三层架构与 MVC 的协作关系

三层架构(表现层、业务层、持久层)与 MVC 并不冲突,而是互补协作:

  • Controller 对应表现层:负责接收请求、参数校验、调用业务层
  • Service 对应业务层:承载核心业务逻辑,对应 MVC 中的 Model 一部分
  • DAO/Repository 对应持久层:负责数据访问,也是 Model 的一部分

在实际项目中,MVC 关注的是「请求如何被接收、处理、渲染」的流程,而三层架构关注的是「业务如何分层、数据如何访问」的结构,两者结合形成完整的应用骨架。

下面用一张图直观展示三层架构与 MVC 的协作关系:

三层架构

MVC 架构

接收请求、参数校验

调用业务层

数据访问

返回数据

封装为 Model

渲染数据

返回响应

Controller(控制器)

Model(模型)

View(视图)

表现层

业务层

持久层

从图中可以看出:Controller 对应表现层,Service 对应业务层,DAO/Repository 对应持久层;而 Model 贯穿业务层与持久层,View 负责最终渲染,两者通过 Controller 串联起完整的请求处理链路。

4.3 MVC 架构解耦、易维护的核心优势

相比传统 Servlet 的「大杂烩」写法,MVC 带来了显著优势:

  • 解耦:视图与业务逻辑分离,修改页面样式不影响业务代码
  • 易维护:每层职责单一,定位问题只需关注对应层
  • 可测试:Model 与 Controller 可以脱离 View 独立单元测试
  • 可复用:同一 Model 可以被多个 View 复用,同一 Controller 可以调用不同 Service

理解了这些优势,就能明白 Spring MVC 为什么采用 DispatcherServlet 作为统一入口,并通过注解驱动来简化开发。

5. Day3:搭建 Spring MVC 基础开发环境

5.1 导入核心 Maven 依赖

创建一个 Maven 工程,在pom.xml中导入 Spring MVC 核心依赖:

<dependencies><!-- Spring MVC 核心 --><dependency><groupId>org.springframework</groupId><artifactId>spring-webmvc</artifactId><version>5.3.30</version></dependency><!-- Servlet API(Tomcat 提供,编译期需要) --><dependency><groupId>javax.servlet</groupId><artifactId>javax.servlet-api</artifactId><version>4.0.1</version><scope>provided</scope></dependency></dependencies>

5.2 完成第一个纯注解驱动的 Spring MVC 入门案例

首先编写一个 Controller,使用纯注解声明请求映射:

@ControllerpublicclassHelloController{@RequestMapping("/hello")@ResponseBodypublicStringhello(@RequestParam(value="name",defaultValue="World")Stringname){return"Hello, "+name+"!";}}

接着编写配置类,启用注解驱动并配置组件扫描:

@Configuration@EnableWebMvc@ComponentScan("com.example.controller")publicclassWebConfigimplementsWebMvcConfigurer{// 可在此配置视图解析器、静态资源等}

最后在web.xml或通过AbstractAnnotationConfigDispatcherServletInitializer注册 DispatcherServlet:

publicclassWebInitializerextendsAbstractAnnotationConfigDispatcherServletInitializer{@OverrideprotectedClass<?>[]getRootConfigClasses(){returnnewClass<?>[0];}@OverrideprotectedClass<?>[]getServletConfigClasses(){returnnewClass<?>[]{WebConfig.class};}@OverrideprotectedString[]getServletMappings(){returnnewString[]{"/"};}}

5.3 验证请求响应全链路通跑

启动 Tomcat 后,访问http://localhost:8080/hello?name=Spring,应返回Hello, Spring!。此时对比 Day1 的手写 Servlet,你会发现:

  • 参数绑定由@RequestParam自动完成,无需手动getParameter
  • 响应由@ResponseBody自动序列化,无需手动拼接 HTML
  • 请求分发由 DispatcherServlet 统一调度,无需手动维护 Servlet 映射

这正是 Spring MVC 在 Servlet 基础上做的封装与升华——理解了 Servlet,才能真正理解 Spring MVC 的设计由来。

6. 总结

通过三天的学习,我们从手写 Servlet 感受传统开发的痛点,到理解 MVC 架构如何解耦,再到用 Spring MVC 跑通全链路,完成了从底层到框架的认知升级。核心收获是:Spring MVC 不是凭空出现的框架,而是对 Servlet 的合理封装与演进。只有吃透 Servlet 底层,才能在后续学习中知其然更知其所以然,避免只会复制粘贴代码。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/29 10:22:52

[AI工程] Spring AI 第十九篇:多 Agent 编排与 A2A——什么时候真该拆,工具箱太大用什么装,跨进程那层 Spring AI 到底给了什么?

&#x1f4a1; 第十四篇写完五种编排模式之后&#xff0c;我在自己的 Demo 上试了"再拆一个 Agent 出来"&#xff1a;调度 Agent 负责分派&#xff0c;专业 Agent 负责查、算、写。结果单测跑通了&#xff0c;链路一拉长就三件事同时冒出来——上下文预算炸了&#x…

作者头像 李华
网站建设 2026/9/29 10:22:48

Unity手游iOS深度链接全流程:从URL Scheme到C#参数投递

Unity 手游 iOS Deep Link 唤醒全流程&#xff1a;从 URL Scheme / Universal Links 到 C# 层参数投递做手游运营或者用户增长的同学应该都有同感&#xff1a;一条短信、一个分享卡片、一个广告点击&#xff0c;用户点下去之后能不能直接落到游戏里的指定界面&#xff0c;直接决…

作者头像 李华
网站建设 2026/9/29 10:19:02

AI漫剧助手:面向漫剧短剧创作者的一站式提示词管理工具

当前AI漫剧、竖屏短剧赛道越来越火热&#xff0c;但很多创作者会耗费大量时间编写、调试提示词&#xff0c;反复处理人物崩脸、画面风格不统一、分镜设计繁琐等问题。AI漫剧助手&#xff0c;是专为漫剧创作者打造的提示词素材管理工具&#xff0c;集成全套漫剧创作资源&#xf…

作者头像 李华
网站建设 2026/9/29 10:17:50

2026年免费AI智能体实测:OpenCode+Ollama本地跑通TaoToken统一Key配置

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/29 10:16:49

AlexNet网络结构逐层拆解与PyTorch实战

前几天有个刚入门的朋友问我&#xff0c;都这个年代了&#xff0c;YOLO系列已经迭代到v11&#xff0c;Transformer在各种任务上横扫榜单&#xff0c;再回头啃一个2012年的AlexNet网络结构&#xff0c;是不是有点浪费时间&#xff1f;我当时没直接回答&#xff0c;而是让他先说说…

作者头像 李华
网站建设 2026/9/29 10:16:33

DC/DC恒压输出控制原理与环路补偿:24V转5V/5A实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华