SpringMVC的DispatcherServlet如何从HTTP Servlet中接收信息
创始人
2025-05-30 20:32:41

本文概述:
从简述 Tomcat 如何处理请求, 然后去探究 SpringMVC 如何去接收请求并通过 Dispatcher 进行派发

Tomcat 如何处理请求的

这里不会特别详细的去说整个流程, 而是简要介绍接收 Servlet 请求是如何处理的.

public class MyFirstServlrt extends HttpServlet {
}   

当我们定义了这样的一个 Servlet ,然后 Tomcat 组件初始化的时候会保存该 Servlet 处理的路径 (本文不讲述这部分), 然后当存在的时候, 才会从 Engine 一直向内发送到 StandardWrapperValve, 这个类中保存的就是 Servlet 实例.
也就是说, 请求到达之后, 是交给了 HTTP Servlet 的子类, 也就是我们定义的类中进行处理
![[Pasted image 20230317223716.png|300]],
可以看见, 我们的定义的所有 HttpServlet 直接继承 HttpSerlvet, 请求经过 HttpServlt 的 service 方法分发到我们定义的 HelloServlet 中的.

    protected void service(HttpServletRequest req, HttpServletResponse resp)throws ServletException, IOException {String method = req.getMethod();if (method.equals(METHOD_GET)) {long lastModified = getLastModified(req);if (lastModified == -1) {// servlet doesn't support if-modified-since, no reason// to go through further expensive logicdoGet(req, resp);} else {long ifModifiedSince;try {ifModifiedSince = req.getDateHeader(HEADER_IFMODSINCE);} catch (IllegalArgumentException iae) {// Invalid date header - proceed as if none was setifModifiedSince = -1;}if (ifModifiedSince < (lastModified / 1000 * 1000)) {// If the servlet mod time is later, call doGet()// Round down to the nearest second for a proper compare// A ifModifiedSince of -1 will always be lessmaybeSetLastModified(resp, lastModified);doGet(req, resp);} else {resp.setStatus(HttpServletResponse.SC_NOT_MODIFIED);}}} else if (method.equals(METHOD_HEAD)) {long lastModified = getLastModified(req);maybeSetLastModified(resp, lastModified);doHead(req, resp);} else if (method.equals(METHOD_POST)) {doPost(req, resp);} else if (method.equals(METHOD_PUT)) {doPut(req, resp);} else if (method.equals(METHOD_DELETE)) {doDelete(req, resp);} else if (method.equals(METHOD_OPTIONS)) {doOptions(req,resp);} else if (method.equals(METHOD_TRACE)) {doTrace(req,resp);} else {String errMsg = lStrings.getString("http.method_not_implemented");Object[] errArgs = new Object[1];errArgs[0] = method;errMsg = MessageFormat.format(errMsg, errArgs);resp.sendError(HttpServletResponse.SC_NOT_IMPLEMENTED, errMsg);}}

经过 Service 方法会根据 HttpMethod 来执行具体的我们定义的 Serlvet 中的方法.

那么 SpringMVC 是如何从 HttpServlet 中接收这个请求的呢, 可能大家都知道 DispatcherServlet 来处理请求? 但是, 你有了解过, 请求如何会到 DispatcherServler 中呢?
先来看看继承图
![[Pasted image 20230124221729.png]]
原先, 请求会到达 HttpServler 的实现子类中, 而 SpringMVC 加入了一个 HTTPServlet, 这个 HttpServlet 就是 DispatcherServlet .这是因为多态嘛.

注意啊, 这里小白可能会不太理解. 请求是按照这个类图往下传递的吗, 然后 SpringMVC 才处理了请求.

先来联想 Tomcat 是如何处理的, 初始化的时候会加载所有的 Servelt, 然后包装起来, 当请求来的时候, 从 Egine 逐层发送到 WrapperServlet, 调用 service 方法, 这个 service 方法是谁的呢, 是 HTTPServlet 接口的的, 而 WrapperServlet 里面是啥的呢, 是一个继承 HTTP Servlet 的类, 也就是我们开发的时候的 Servlet.

所以说, 直接接收请求的其实就是 WrapperServlet 里面的 Servlet, 但是因为多态嘛, 子类拥有父类的方法, 先调用了父类的方法, 然后才调用了子类的方法.
举个例子 HelloServlet 在处理请求的时候, 会先调用其 service 方法, 然后 service 方法进行判断, 然后直接强转然后调用了子类的方法 (强转意味着什么, 其实从真实保存的数据来说, 这个 Servlet 就是一个我们创建的 Servlet)

    @Overridepublic void service(ServletRequest req, ServletResponse res)throws ServletException, IOException {HttpServletRequest  request;HttpServletResponse response;try {request = (HttpServletRequest) req;response = (HttpServletResponse) res;} catch (ClassCastException e) {throw new ServletException(lStrings.getString("http.non_http"));}service(request, response);}

然后此时我们再来看看 SpringMVC 如何处理的可能就有体会了.
SpringMVC 创建的就是一个 HTTPServlet, 不过是实现的子类
![[Pasted image 20230124221729.png]]
DispatcherServelt 此时其实就是清晰了, Servevlt 其实就是 DispatcherServelt, 其等于 HttpServlet, 等于 HttpServletBean, 等于 FrameWork, 然后在接受请求的时候, 首先到了 HttpServlet 对吧
然后我们实现了一个 FrameWorkServlet, 然后发送到了 FreameworkdServlet,.
FrameworkServlet 就有意思了, 是 MVC 自定义的, 也就是说让其调用子类的方法就可以了 (因为本质上存储的就是 DispatcherServlet, 只是先调用了父类方法, 但是父类方法也可以调用子类方法, 具体可以了解模板方法, 父类定义流程, 子类实现流程中核心步骤)

也就是说 DispatcherServlet 也就是实现了 HttpServlet 接口的一个自定义的 Servlet, 和我们创建的一样, 但是他强了很多倍.
DispatcherServlet 在处理的时候, 还是和普通的 servlet 一样, 先是 service 方法, 但是但是, 因为 Dispatcher Servlet 的父类 FrameworkServlet 就实现了 service 方法, 这里要思考, 原本 HTTPservlet 调用 service 方法是调用的 HelloServlet 父类的 service 方法, 而 FrameWorkServlet 就有 service 方法, 现在是不是是不是,dispatcherServlet 要调用 FrameWorkServlet 的 service 方法

	@Overrideprotected void service(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {HttpMethod httpMethod = HttpMethod.resolve(request.getMethod());if (httpMethod == HttpMethod.PATCH || httpMethod == null) {//processRequest(request, response);}else {super.service(request, response);}}
	protected final void processRequest(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {long startTime = System.currentTimeMillis();Throwable failureCause = null;LocaleContext previousLocaleContext = LocaleContextHolder.getLocaleContext();LocaleContext localeContext = buildLocaleContext(request);RequestAttributes previousAttributes = RequestContextHolder.getRequestAttributes();ServletRequestAttributes requestAttributes = buildRequestAttributes(request, response, previousAttributes);WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);asyncManager.registerCallableInterceptor(FrameworkServlet.class.getName(), new RequestBindingInterceptor());initContextHolders(request, localeContext, requestAttributes);try {// DispatcherServlet正式进场了!!!!doService(request, response);}... 省略

OK, 到这里就结束了,SpringMVC 之所以能接收所有的 Servlet 请求, 本质上是因为 DispatcherServlet 也是一个普通的 Servlet, 每个我们创建的 Servlet 在执行我们的业务代码之前都需要执行 service 方法, 而 DispatcherServlet 的父类就有 service 方法, 所以就屏蔽了父类的 service 方法, 然后 FrameworkServlet 是 MVC 自定义的抽象类, 所以理所当然的把消息传给亲儿子 DisapatcherServlet 来处理

![[Pasted image 20230318161457.png]]
不知道大家还记不记得, 如果是 xml 配置 SpringMVC, 我们设置了一个属性, 就是配置的映射路径, 我们给 DispatcherServlet 设置的是 “/”

...省略标签dispatcherServlet/

也就是说, 就是这里配置的 Serlvet, Tomcat 初始化的时候会加载这里的信息 (不是创建), 然后当请求的时候, 会接手所有根路径下的请求, 也就是请求就到了 DispatcherServlet, 然后他就先调用 service 方法, 即 FrameWorkServlet 的 service 方法, 最后调用 doDispatcher 方法.

相关内容

热门资讯

GDPU C语言 天码行空3 1. 分段函数 #includeint main(){double x,y;scanf("%lf",...
【瑞萨 MCU】开发环境搭建之... e2 studio e2 studio(简称为 e2 或 e2s)是瑞萨...
C语言内联汇编 之前我们介绍了一种C语言与汇编代码混合编程方式,就是两个文件分开编写,分...
Linux 网络编程学习笔记—... 一、TCP 服务的特点 传输层协议主要有 TCP 协议和 UDP 协议,前者相对于后者...
KubeSphere All ... KubeSphere All in one安装配置手册 1. 初始化 1.1 配置apt源 # vi...
学习软件测试怎么能缺少练手的软... 你好,我是凡哥。 最近收到许多自学自动化测试的小伙伴私信,学习了理论知识...
【面试题】浅谈css加载是否会... 大厂面试题分享 面试题库前后端面试题库 (面试必备) 推荐:...
直播带货系统开发的关键点、代码... 时下,直播的热度依然不减,而它的产物之一:直播带货系统&#...
一文读懂强化学习! 一.了解强化学习1.1基本概念强化学习是考虑智能体(Agent)与环境&...
Spring Cloud之一:... 目录 环境 Eureka工程的创建步骤 系列目录(持续更新。。。) S...
golang实现守护进程(2) 前言golang实现守护进程,包含功能:1. 守护进程只创建一次2. 平...
url 格式详解 统一资源定位系统(uniform resource locator; url ...
elasticsearch7.... elasticsearch版本:7.17.3 目标:实现对类型为text...
SpringBoot 加载系统... 开发环境: IDEA 2022.1.4+ MyBatis         代码参考:spri...
交换机概念和知识和命令 目录 一、华为交换机基础学习的一些重要概念和知识 二、交换机常用命令大全 三、不常用的交换机命令 ...
什么是 JavaScript ... 本文首发自「慕课网」,想了解更多IT干货内容,程序员圈内热闻࿰...
【C++】C++11——lam... 文章目录一、Lambda表达式引入二、Lambda表达式语法三、Lambda表达式交换两个值四、La...
Java分布式事务(十) 文章目录🔥分布式架构的理论知识_BASE理论🔥分布式事务解决方案_最...
vmware中centos7实... 前言 在开发收银系统SAAS版本时,采用的是centos服务器,经常需要...
计算机图形学 | 可编程渲染管... 计算机图形学 | 可编程渲染管线计算机图形学 | 可编程渲染管线3.1 从固定到可编程图形编程的发展...
linux下安装两个或多个to... 安装jdk,tomcat编辑环境变量profilevi /etc/profile加入以...
selenium的显示等待、隐... 关于selenium有三种等待方式,分别为显示等待、隐式等待、强制等待 1、强制等待 ...
测牛学堂:软件测试接口自动化之... requests库 用postman进行接口测试有一定的限制,我们测试更应该掌握的是用...
day36_jdbc 今日内容 上课同步视频:CuteN饕餮的个人空间_哔哩哔哩_bilibili 同步笔记沐沐霸的博客...
【java基础】Stream流... 文章目录基本介绍流的创建流的各种常见操作forEach方法filter方法map方法peek方法fl...
幂等性通用组件 一、什么是幂等性幂等是一个数学与计算机学概念,在数学中某一元运算为幂等时,...
Nacos服务注册 又是美好的一天呀~ 个人博客地址: huanghong.top 本文预估阅读时长为3...
令人惊艳的ChatGPT项目,... 自从 ChatGPT、Stable Diffusion 发布以来,各种相关开源项目百花...
舆情监测系统有哪些优势,TOO... 舆情监测系统是一种基于大数据技术的舆情分析工具,可以帮助企业、政府等机构实时监控公众对...
【Linux】基础IO流(上) 文章目录1. 预备知识2. 回忆C接口fopenfputsfprintfsnprintf追加方式——...