【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基础操作的理想…...

OpenCV中使用EdgeDrawing模块查找圆
从OpenCV4.5.2开始,Contrib模块中封装了开源库ED_Lib用于查找图像中的直线、线段、椭圆和圆。Github地址: https://github.com/CihanTopal/ED_Lib 算法原理简介: 边缘绘制(ED)算法是一种解决边缘检测问题的主动方法…...

C++在游戏领域的主要应用
1、C简介 C是一种通用的程序设计语言,其设计就是为了使认真的程序员工作得更愉快。除了一些小细节之外,C是C程序设计语言的一个超集。C提供了C所提供的各种功能还为定义新类型提供了灵活而有效的功能。程序员可以通过定义新类型,使这些类型与…...

基于SpringBoot的“CSGO赛事管理系统”的设计与实现(源码+数据库+文档+PPT)
基于SpringBoot的“CSGO赛事管理系统”的设计与实现(源码数据库文档PPT) 开发语言:Java 数据库:MySQL 技术:SpringBoot 工具:IDEA/Ecilpse、Navicat、Maven 系统展示 系统首页界面图 赛事信息界面图 赛事通知界面…...

Web Broker(Web服务应用程序)入门教程(2)
1. Web 调度器(Web Dispatcher) 如果您使用的是 Web 模块,它就充当 Web 调度器的角色。如果您使用的是现成的数据模块,则必须向该数据模块中添加一个单一的调度器组件(Web.HTTPApp.TWebDispatcher)。调度器维护着一个动作项集合,这些动作项知道如何处理特定类型的请求消息…...

redis:list列表命令和内部编码
个人主页 : 个人主页 个人专栏 : 《数据结构》 《C语言》《C》《Linux》《网络》 《redis学习笔记》 文章目录 前言命令LPUSH 和 LPUSHXLRANGERPUSH 和 RPUSHXLPOP 和 RPOPLINDEXLINSERTLLENLREMLTRIMLSET阻塞版命令BLPOP 和 BRPOP 内部编码总结 前言 列…...

.Net Core Configuration用法
//在应用程序的任何地方注入 IConfiguration 来访问配置数据。ASP.NET Core 默认会加载 appsettings.json 文件 IConfiguration _configuration builder.Configuration; string connectionString _configuration["ConnectionStrings:SqlServerConnection"]; Hel…...

分享一些企业选择管理顾问公司的成功经验
为了在激烈的市场竞争中脱颖而出,许多企业开始寻求外部专业力量的支持,其中,企业管理顾问公司以其专业的知识、丰富的经验和独到的见解,成为了众多企业的得力助手。本文将分享一些企业在选择企业管理顾问公司过程中的成功经验&…...

「Qt Widget中文示例指南」如何实现窗口嵌入?
Qt 是目前最先进、最完整的跨平台C开发工具。它不仅完全实现了一次编写,所有平台无差别运行,更提供了几乎所有开发过程中需要用到的工具。如今,Qt已被运用于超过70个行业、数千家企业,支持数百万设备及应用。 本文中的示例主要演…...

企业CRM选型必看:2024年最佳CRM系统排行
企业用户在选择CRM系统时,不仅要考虑系统的功能性、可定制性,还要考虑其与现有工具的集成能力以及价格。此外,在2024年,越来越多的企业用户会把CRM厂商的AI能力列入考察范畴。 本文分析整理2024年最佳CRM系统排行榜,从…...

SQL入门的基础知识
思考 无论是干任何语言或者其他方向的开发,都会和我们的SQL去进行打交道 总结 学习SQL的原因:后面的实战案例需要用SQL,SQL是开发人员的必备技能 现在只需要学到满足后续案例需要,即简单增删改查,做一个入门即可 1.…...