【Spring MVC】DispatcherServlet 请求处理流程
一、 请求处理
Spring MVC 是 Spring 框架的一部分,用于构建 Web 应用程序。它遵循 MVC(Model-View-Controller)设计模式,将应用程序分为模型(Model)、**视图(View)和控制器(Controller)**三个部分。
DispatcherServlet 处理流程:

- 当用户发起请求时,会将请求直接传入前端控制器
DispatcherServlet,它是 Spring MVC 核心组件,负责接收请求并分发到各自的处理器中 - DispatcherServlet 接收到请求后,会调用
HandlerMapping组件。HandlerMapping 根据请求的 URL 查找合适的处理器(Handler)。这里的Handler通常是指Controller中的方法,这些方法通常带有 @RequestMapping 注解(或其变体如 @GetMapping , @PostMapping 等)。 - DispatcherServlet 获取到合适的
Handler后,会调用HandlerAdapter组件。HandlerAdapter 负责执行处理器方法,并处理方法的返回值。HandlerAdapter同样会去 Handler (Controller)中找那些带有 @RequestMapping 注解的方法 HandlerAdapter调用 Controller 中的方法,执行业务逻辑。处理完业务后,会返回一个ModelAndView对象给 HandlerAdapter。ModelAndView 对象中包含模型数据(Model)和视图名称(View)。- DispatcherServlet 从 HandlerAdapter 获取到
ModelAndView对象后,会调用ViewResolver组件。ViewResolver 负责将视图名称解析为实际的视图对象。 DispatcherServlet获取到具体的视图对象后,将模型数据传递给视图对象View进行渲染。- 渲染完成后,
DispatcherServlet将生成的响应内容返回给用户,浏览器显示最终的页面。

- 客户端发出请求,会先经过 filter 过滤,通过的请求才能到达 DispatcherServlet。
- DispatcherServlet 通过 handlerMapping 找到请求对应的 handler,返回一个 HandlerExecutionChain 里面包含 interceptors 和 handler
- DispatcherServlet 通过 handlerAdapter 调用实际的 handler 处理业务逻辑, 返回 ModelAndView。里面会包含逻辑视图名和 model 数据。注意,在此之前和之后,会分别调用 interceptors 拦截处理
- 调用 viewResolver 将逻辑视图名解析成 view 返回
- 调用 view.render 渲染视图,写进 response。然后 interceptors 和 filter 依次拦截处理,最后返回给客户端
HandlerInterceptor
拦截器。在 handler 执行前后及视图渲染后执行拦截,可以注册不同的 interceptor 定制工作流程
public interface HandlerInterceptor {// 在 handler 执行前拦截,返回 true 才能继续调用下一个 interceptor 或者 handlerdefault boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {return true;}// 在 handler 执行后,视图渲染前进行拦截处理default void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,@Nullable ModelAndView modelAndView) throws Exception {}// 视图渲染后,请求完成后进行处理,可以用来清理资源// 除非 preHandle 放回 false,否则一定会执行,即使发生错误default void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler,@Nullable Exception ex) throws Exception {}}
二、设计原理
Servlet 规范
SpringMVC 是基于 Servlet 的。
Servlet 是运行在 web 服务器上的程序,它接收并响应来自 web 客户端的请求(通常是 HTTP 请求)。
Servlet 规范有三个主要的技术点: Servlet, Filter, Listener
1. Servlet
Servlet 是实现 Servlet 接口的程序。对于 HTTP, 通常继承 javax.servlet.http.HttpServlet, 可以为不同的 URL 配置不同的 Servlet。Servlet 是"单例"的,所有请求共用一个 Servlet, 因此对于共享变量(比如实例变量),需要自己保证其线程安全性。DispatcherServlet 便是一个 Servlet。
Servlet 生命周期
- Servlet 实例化后,Servlet 容器会调用
init方法初始化。init 只会被调用一次,且必须成功执行才能提供服务。 - 客户端每次发出请求,Servlet 容器调用
service方法处理请求。 - Servlet 被销毁前,Servlet 容器调用
destroy方法。通常用来清理资源,比如内存,文件,线程等。
2. Filter
Filter 是过滤器,用于在客户端的请求访问后端资源之前,拦截这些请求;或者在服务器的响应发送回客户端之前,处理这些响应。只有通过 Filter 的请求才能被 Servlet 处理。
Filter 可以通过配置(xml 或 java-based)拦截特定的请求,在 Servlet 执行前后(由 chain.doFilter 划分)处理特定的逻辑,如权限过滤,字符编码,日志打印,Session 处理,图片转换等
Filter 生命周期
-
Filter 实例化后,Servlet 容器会调用
init方法初始化。init 方法只会被调用一次,且成功执行(不抛出错误且没有超时)才能提供过滤功能 -
客户端每次发出请求,Servlet 容器调用
doFilter方法拦截请求。public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws java.io.IOException, ServletException {// 客户端的请求访问后端资源之前的处理逻辑System.out.println("我在 Servlet 前执行");// 把请求传回过滤链,即传给下一个 Filter, 或者交给 Servlet 处理chain.doFilter(request,response);// 服务器的响应发送回客户端之前的处理逻辑System.out.println("我在 Servlet 后执行"); } -
Filter 生命周期结束时调用
destroy方法,通常用来清理它所持有的资源,比如内存,文件,线程等。
3. Listener
Listener 是监听某个对象的状态变化的组件,是一种观察者模式。
被监听的对象可以是域对象 ServletContext, Session, Request
监听的内容可以是域对象的创建与销毁,域对象属性的变化
| ServletContext | HttpSession | ServletRequest | |
|---|---|---|---|
| 对象的创建与销毁 | ServletContextListener | HttpSessionListener | ServletRequestListener |
| 对象的属性的变化 | ServletContextAttributeListener | HttpSessionAttributeListener | ServletRequestAttributeListener |
WebApplicationContext
SpringMVC 用 Spring 化的方式来管理 web 请求中的各种对象。
什么是 Spring 化? IOC 和 AOP, 这不是本文的重点,具体自行查阅。
SpringMVC 会通过 WebApplicationContext 来管理服务器请求中涉及到的各种对象和他们之间的依赖关系。
WebApplicationContext 继承自 ApplicationContext, 它定义了一些新的作用域,提供了 getServletContext 接口。
public interface WebApplicationContext extends ApplicationContext {// 根容器名,作为 key 存储在 ServletContext 中; ServletContext 持有的 WebApplicationContextString ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE = WebApplicationContext.class.getName() + ".ROOT";/*** 这三个是 WebApplicationContext 特有的作用域* 通过 WebApplicationContextUtils.registerWebApplicationScopes 注册相应的处理器*/String SCOPE_REQUEST = "request";String SCOPE_SESSION = "session";String SCOPE_APPLICATION = "application";/*** ServletContext 在 WebApplicationContext 中的名字* 通过 WebApplicationContextUtils.registerEnvironmentBeans 注册到 WebApplicationContext 中*/String SERVLET_CONTEXT_BEAN_NAME = "servletContext";/*** ServletContext 和 ServletConfig 配置参数在 WebApplicationContext 中的名字* ServletConfig 的参数具有更高的优先级,会覆盖掉 ServletContext 中的参数* 值为 Map<String, String> 结构*/String CONTEXT_PARAMETERS_BEAN_NAME = "contextParameters";/*** ServletContext 属性信息在 WebApplicationContext 中的名字* 值为 Map<String, String> 结构* 属性是用来描述 ServletContext 本身的一些信息的*/String CONTEXT_ATTRIBUTES_BEAN_NAME = "contextAttributes";/*** 获取 ServletContext 接口*/@NullableServletContext getServletContext();}
WebApplicationContext 类图

ApplicationContext 有一个抽象实现类 AbstractApplicationContext, 模板方法的设计模式。它有一个 refresh 方法,它定义了加载或初始化 bean 配置的基本流程。后面的实现类提供了不同的读取配置的方式,可以是 xml, annotation, web 等,并且可以通过模板方法定制自己的需求。
AbstractApplicationContext 有两个实现体系, 他们的区别是每次 refresh 时是否会创建一个新的 DefaultListableBeanFactory。DefaultListableBeanFactory 是实际存放 bean 的容器, 提供 bean 注册功能。
- AbstractRefreshableApplicationContext 这个 refreshable 并不是指 refresh 这个方法,而是指 refreshBeanFactory 这个方法。他会在每次 refresh 时创建一个新的 BeanFactory(DefaultListableBeanFactory)用于存放 bean,然后调用 loadBeanDefinitions 将 bean 加载到新创建的 BeanFactory。
- GenericApplicationContext 内部持有一个 DefaultListableBeanFactory, 所以可以提前将 Bean 加载到 DefaultListableBeanFactory, 它也有 refreshBeanFactory 方法,但是这个方法啥也不做。
根据读取配置的方式,可以分成 3 类,基于 xml 的配置, 基于 annotation 的配置和基于 java-based 的配置
- 基于 xml 的配置使用 xml 作为配置方式, 此类的名字都含有 Xml, 比如从文件系统路径读取配置的 FilePathXmlApplicationContext, 从 ClassPath 读取配置的 ClassPathXmlApplicationContext, 基于 Web 的 XmlWebApplicationContext 等
- 基于注解的配置通过扫描指定包下面具有某个注解的类,将其注册到 bean 容器,相关注解有 @Component, @Service, @Controller, @Repository,@Named 等
- java-based 的配置方式目前是大势所趋,结合注解的方式使用简单方便易懂,主要是 @Configuration 和 @Bean
上面几个类是基础类,下面是 SpringMVC 相关的 WebApplicationContext
-
XmlWebApplicationContext 和 AnnotationConfigWebApplicationContext 继承自 AbstractRefreshableApplicationContext,表示它们会在 refresh 时新创建一个 DefaultListableBeanFactory, 然后 loadBeanDefinitions。 它们分别从 xml 和 注解类(通常是 @Configuration 注解的配置类)中读取配置信息。
-
XmlEmbeddedWebApplicationContext 和 AnnotationConfigEmbeddedWebApplicationContext 继承自 GenericApplicationContext,表示他们内部持有一个 DefaultListableBeanFactory, 从名字可以看出它们是用于 “Embedded” 方面的,即 SpringBoot 嵌入容器所使用的 WebApplicationContext
-
SpringMVC 应用中几乎所有的类都交由 WebApplicationContext 管理,包括业务方面的 @Controller, @Service, @Repository 注解的类, ServletContext, 文件处理 multipartResolver, 视图解析器 ViewResolver, 处理器映射器 HandleMapping 等。
相关文章:
【Spring MVC】DispatcherServlet 请求处理流程
一、 请求处理 Spring MVC 是 Spring 框架的一部分,用于构建 Web 应用程序。它遵循 MVC(Model-View-Controller)设计模式,将应用程序分为模型(Model)、**视图(View)和控制器&#x…...
【优选算法】——二分查找!
目录 1、二分查找 2、在排序数组中查找元素的第一个和最后一个位置 3、搜索插入位置 4、x的平方根 5、山脉数组的封顶索引 6、寻找峰值 7、寻找旋转排序数组中的最小值 8、点名 9、完结散花 1、二分查找 给定一个 n 个元素有序的(升序)整型数组…...
leetcode hot100【LeetCode 300. 最长递增子序列】java实现
LeetCode 300. 最长递增子序列 题目描述 给定一个未排序的整数数组 nums,找出其中最长递增子序列的长度。 要求: 子序列是由数组派生而来的序列,删除(或不删除)数组中的元素而不改变其余元素的顺序。例如࿰…...
sql注入——靶场Less1
?id1 ?id99union select 1,2,3-- 查看占位 ?id1 order by 3-- 尝试出表有几列 ?id1 order by 4-- 说明只有三列 ?id99 union select 1,database(),3-- 查询当前使用的数据库的名称 ?id99 union select 1,group_concat(table_name),3 from information_schema.tables …...
docker file容器化部署Jenkins(一)
Jenkins Github地址:https://github.com/jenkinsci/jenkins 国内镜像地址:https://docker.aityp.com/ 准备工作 # 创建持久化卷目录 mkdir /data/jenkins_home/Jenkins拉取镜像 # 由于Jenkins需要JDK,所以直接拉取带有JDK的Jenkins镜像 doc…...
ArkTS组件继承的高级用法
在HarmonyOS应用开发中,ArkTS作为开发语言,组件的继承是实现代码复用和扩展功能的重要机制。本文将详细介绍ArkTS中组件继承的高级用法,包括继承的概念、如何使用继承、以及继承在实际开发中的应用和最佳实践。 继承的概念 继承是面向对象编…...
第十二章 spring Boot+shiro权限管理
学习目标 引入依赖配置Shiro设计数据库表编写Mapper、Service和Controller前端页面测试与调优其他注意事项 Spring Boot与Shiro的集成是一种常见的Java Web应用程序权限管理解决方案。Shiro是一个强大的Java安全框架,提供了认证、授权、会话管理、加密等安全功能。以…...
jmeter基础01-3_环境准备-Linux系统安装jdk
Step1. 查看系统类型 打开终端,命令行输入uname -a,显示所有系统信息,包括内核名称、主机名、内核版本等。 如果输出是x86_64,则系统为64位。如果输出是i686 或i386,则系统为32位。 Step2. 官网下载安装包 https://www…...
数字证书的简单记录
CA(Certificate Authority):即数字证书颁发认证机构。 CA数字证书(crt/cer证书):数字证书 申请者与颁发者信息申请者公钥颁发者签名,由CA机构使用私钥签名得到数字证书。 CA中间证书࿱…...
ssm基于SSM的校内信息服务发布系统的设计与实现+vue
系统包含:源码论文 所用技术:SpringBootVueSSMMybatisMysql 免费提供给大家参考或者学习,获取源码看文章最下面 需要定制看文章最下面 目 录 摘要 1 Abstract 1 目 录 2 1绪论 4 1.1研究背景与意义 4 1.2国内外研究现状 4 1.3研究…...
Java 教程简介
Java 教程简介 Java 是 Sun Microsystems 公司于 1995 年 5 月推出的一种面向对象的编程语言和运行平台,由 James Gosling 和他的同事共同研发。当前,这个产品已被 Oracle 公司所收购。这篇教程将带你了解 Java 的一些基础知识和应用。 Java 系统简介 …...
【C/C++】【三种方法】模拟实现strlen
学习目标: 使用代码模拟实现strlen。 逻辑: strlen 需要输入一个字符串数组类型的变量,并且返回一个整型类型的数据。strlen 需要计算字符串数组有多少个元素。 代码1:使用计数器 #define _CRT_SECURE_NO_WARNINGS 1 #include&…...
外贸平台开发多语言处理的三种方式
随着全球贸易的不断增长,外贸平台的多语言处理已成为提升用户体验和市场竞争力的重要因素。在开发外贸平台时,有多种方法可以实现多语言支持。本文将探讨三种主要的多语言处理方式:数据库级多语言支持、前端国际化框架以及内容管理系统&#…...
学习GCC
浅显易懂的GCC使用教程——初级篇_gcc -ddebug-CSDN博客 本文摘抄学习自上面的文章! GCC: GNU Compiler Collection: GNU编译器套件,属于一种编程语言编译器,其原名为GCC(GNU C Compiler),即GNU c语言编译器,虽然缩写…...
B2109 统计数字字符个数
B2109 统计数字字符个数 #include <iostream> using namespace std; # include <string.h> #include <ctype.h> #include <algorithm> int main(){ char str[256]; cin.getline(str,256); //fgets(str,256,stdin); int cnt 0; //for(size_t i 0…...
springboot Lark扫码登录
登录流程 测试通过的地址: https://open.larksuite.com/open-apis/authen/v1/index?app_idcli_a7add3c5bb38902f&redirect_urihttp%3A%2F%2Fstrongculture.cn&stateSTATE...
中专女生数赛疑云:阿里蒙冤,学校之过,尽显世态炎凉
11月3日,阿里巴巴全球数学竞赛组委会发布2024阿里巴巴全球数学竞赛有关情况说明:在本届竞赛中,江苏省涟水中等专业学校教师王某某和其指导的学生入围决赛,引发社会关注。根据决赛阅卷结果,二人未获奖。据调查了解&…...
【neo4j】 图数据库neo4j cypher单一语句 optional 可选操作的技巧
neo4j cypher单一语句 optional 可选操作的技巧 参考文章: Optional merge on relationships Cyper Merge on Optional Match 背景: 使用 match some node 中间还有一些可能与此node有联系的关系或者节点需要处理 create/merge/delete MATCH (src:SOU…...
ip地址分为几大类-IP和子网掩码对照表
一、IP地址的基本概念与分类 IP地址是用于在网络中标识每个设备的逻辑地址。互联网协议将IP地址分为A、B、C、D和E五类,其中A、B、C三类最常用,它们主要根据地址的首位位数以及用途进行划分。 A类地址: 范围:0.0.0.0 - 127.255.2…...
第四篇: 用Python和SQL在BigQuery中进行基础数据查询
用Python和SQL在BigQuery中进行基础数据查询 在大数据分析领域,Google BigQuery 提供了一种快速且经济高效的数据处理方式。对于想要使用SQL查询大规模数据的读者来说,BigQuery的公共数据集资源丰富、操作简便,是学习和实践SQL基础操作的理想…...
MongoDB Limit 与 Skip 方法详解
MongoDB Limit 与 Skip 方法详解 引言 MongoDB 是一个高性能、可伸缩的文档存储系统,它提供了强大的数据存储和查询功能。在处理大量数据时,Limit 与 Skip 方法是 MongoDB 中常用的查询优化工具。本文将详细介绍 MongoDB 中的 Limit 与 Skip 方法,包括其基本用法、性能影响…...
LangGraph状态机工程:构建复杂AI工作流的完整指南
传统RAG(检索增强生成)在处理简单的"单跳"问题时表现良好——“文章里提到了什么” “这个概念是什么意思”——但当问题涉及多个实体之间的关系、需要跨多个文档推理时,传统RAG就显得力不从心。GraphRAG(Graph-based R…...
具身智能:面向新兴交叉学科建设的思考与建议 2026
这份由 CCF YOCSEF 长三角五地学术委员会 2026 年 5 月发布的白皮书,聚焦具身智能作为新兴交叉学科的建设,明确其并非 AI 与机器人学的简单拼接,而是围绕物理交互中的智能行为形成的新问题域,提出 “三大基本问题 一个应用需求”…...
百度深度学习研究院的“叛将“,带着一颗芯片改变了中国智能驾驶——地平线余凯,从ImageNet冠军到征程出货1000万
大家好,我是写代码的篮球球痴。这篇文章跟我自己有点关系——我开的是理想汽车。理想的智驾系统 AD Pro,搭载的就是地平线征程 5 芯片。2026 年 1 月理想 AD Pro 4.0 推送,基于单颗征程 6M 实现了城市 NOA——这是行业里第一个用单颗 128TOPS…...
Unity3D深度纹理实战:手把手教你实现可交互的激光雷达扫描特效(附完整C#/Shader代码)
Unity3D深度纹理实战:手把手教你实现可交互的激光雷达扫描特效(附完整C#/Shader代码)在科幻题材的游戏开发中,激光雷达扫描特效是营造科技感的经典元素。从《赛博朋克2077》的战术目镜到《看门狗》的环境扫描,这种动态…...
模式分层预测驱动推断:处理复杂缺失数据的统计新框架
1. 项目概述:当数据“缺胳膊少腿”时,如何做出靠谱的推断?在数据科学和统计建模的日常工作中,我们最怕遇到什么?不是复杂的算法,也不是海量的数据,而是数据本身“缺胳膊少腿”——也就是缺失值。…...
自动加字幕软件推荐:口播视频如何批量加字幕过
口播视频加字幕,为什么越做越累?一位知识类博主连续两周日更3条口播视频,每条12–18分钟,需手动校对字幕、拆分金句切片、补气口停顿、匹配背景音乐——最后一条视频发布时,字幕错漏率达17%,平台审核未过。…...
别再手动改代码了!用Vivado的VIO IP核实时调试你的FPGA设计(附UART实例)
实时交互式FPGA调试革命:Vivado VIO核的UART实战指南 调试FPGA设计时,你是否经历过这样的痛苦循环:修改一行代码→全编译→下载比特流→测试→发现问题→再修改...这种"石器时代"的工作流正在吞噬工程师的创造力。Xilinx Vivado中的…...
【独家首发】DeepSeek官方未公开的集成测试Checklist(含23项生产环境准入阈值与压测基线)
更多请点击: https://codechina.net 第一章:DeepSeek集成测试方案 DeepSeek模型的集成测试需覆盖推理服务稳定性、多模态输入兼容性、上下文长度边界及API协议一致性四大核心维度。测试环境基于Kubernetes集群部署,采用PrometheusGrafana监控…...
拒绝繁琐 PS:美图秀秀 电脑版在技术博客配图、无畸变裁剪与尺寸标准化中的应用
在日常开发、技术写作或维护 GitHub 开源项目时,技术配图和录屏展示是不可或缺的组成部分。 然而,对于大多数程序员和前端开发者来说,仅仅为了裁剪一个 App Icon 尺寸、给一系列产品图加防伪水印、对系统敏感配置截图进行脱敏打码࿰…...
