【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基础操作的理想…...
龙虎榜——20250610
上证指数放量收阴线,个股多数下跌,盘中受消息影响大幅波动。 深证指数放量收阴线形成顶分型,指数短线有调整的需求,大概需要一两天。 2025年6月10日龙虎榜行业方向分析 1. 金融科技 代表标的:御银股份、雄帝科技 驱动…...
在软件开发中正确使用MySQL日期时间类型的深度解析
在日常软件开发场景中,时间信息的存储是底层且核心的需求。从金融交易的精确记账时间、用户操作的行为日志,到供应链系统的物流节点时间戳,时间数据的准确性直接决定业务逻辑的可靠性。MySQL作为主流关系型数据库,其日期时间类型的…...
为什么需要建设工程项目管理?工程项目管理有哪些亮点功能?
在建筑行业,项目管理的重要性不言而喻。随着工程规模的扩大、技术复杂度的提升,传统的管理模式已经难以满足现代工程的需求。过去,许多企业依赖手工记录、口头沟通和分散的信息管理,导致效率低下、成本失控、风险频发。例如&#…...
剑指offer20_链表中环的入口节点
链表中环的入口节点 给定一个链表,若其中包含环,则输出环的入口节点。 若其中不包含环,则输出null。 数据范围 节点 val 值取值范围 [ 1 , 1000 ] [1,1000] [1,1000]。 节点 val 值各不相同。 链表长度 [ 0 , 500 ] [0,500] [0,500]。 …...
ESP32 I2S音频总线学习笔记(四): INMP441采集音频并实时播放
简介 前面两期文章我们介绍了I2S的读取和写入,一个是通过INMP441麦克风模块采集音频,一个是通过PCM5102A模块播放音频,那如果我们将两者结合起来,将麦克风采集到的音频通过PCM5102A播放,是不是就可以做一个扩音器了呢…...
如何为服务器生成TLS证书
TLS(Transport Layer Security)证书是确保网络通信安全的重要手段,它通过加密技术保护传输的数据不被窃听和篡改。在服务器上配置TLS证书,可以使用户通过HTTPS协议安全地访问您的网站。本文将详细介绍如何在服务器上生成一个TLS证…...
Cloudflare 从 Nginx 到 Pingora:性能、效率与安全的全面升级
在互联网的快速发展中,高性能、高效率和高安全性的网络服务成为了各大互联网基础设施提供商的核心追求。Cloudflare 作为全球领先的互联网安全和基础设施公司,近期做出了一个重大技术决策:弃用长期使用的 Nginx,转而采用其内部开发…...
蓝桥杯 冶炼金属
原题目链接 🔧 冶炼金属转换率推测题解 📜 原题描述 小蓝有一个神奇的炉子用于将普通金属 O O O 冶炼成为一种特殊金属 X X X。这个炉子有一个属性叫转换率 V V V,是一个正整数,表示每 V V V 个普通金属 O O O 可以冶炼出 …...
【Go语言基础【12】】指针:声明、取地址、解引用
文章目录 零、概述:指针 vs. 引用(类比其他语言)一、指针基础概念二、指针声明与初始化三、指针操作符1. &:取地址(拿到内存地址)2. *:解引用(拿到值) 四、空指针&am…...
Redis:现代应用开发的高效内存数据存储利器
一、Redis的起源与发展 Redis最初由意大利程序员Salvatore Sanfilippo在2009年开发,其初衷是为了满足他自己的一个项目需求,即需要一个高性能的键值存储系统来解决传统数据库在高并发场景下的性能瓶颈。随着项目的开源,Redis凭借其简单易用、…...
