【Spring6源码・MVC】请求处理流程源码解析
上一篇《【Spring6源码・MVC】初始化registry,完成url和controller的映射关系》我们知道,在IOC容器加载的同时,初始化了registry这个HashMap,这个HashMap中存放了请求路径和对应的方法。当我们请求进来,会通过这个registry去获取对应的方法。
在SpringBoot项目启动的时候,会加载一个线程:

步入run方法:

步入run方法:
当前这个类是Worker:Class Worker 主要维护运行任务的线程的中断控制状态,以及其他次要簿记。此类适时地扩展了 AbstractQueuedSyncer,以简化获取和释放围绕每个任务执行的锁。这可以防止旨在唤醒等待任务的工作线程而不是中断正在运行的任务的中断。我们实现了一个简单的非重入互斥锁,而不是使用 ReentrantLock,因为我们不希望工作线程任务在调用池控制方法(如 setCorePoolSize)时能够重新获取锁。此外,为了在线程实际开始运行任务之前抑制中断,我们将锁定状态初始化为负值,并在启动时清除它(在 runWorker 中)。
这个run方法主要是启动主运行循环,以此从队列中取出task执行。

当我们发送一个请求时:http://localhost:8081/user/test
会调用这个runWorker方法中的task.run():
runWorker这个方法是主工作线程运行循环。反复从队列中获取任务并执行它们,同时处理许多问题:
- 我们可以从初始任务开始,在这种情况下,我们不需要获取第一个任务。否则,只要池正在运行,我们就从getTask获取任务。如果它返回 null,则工作线程由于池状态或配置参数更改而退出。其他退出是由外部代码中的异常抛出引起的,在这种情况下,complete突然持有,这通常会导致processWorkerExit替换此线程。
- 在运行任何任务之前,获取锁以防止在任务执行时出现其他池中断,然后我们确保除非池停止,否则该线程没有设置中断。
- 每次任务运行之前都会调用 beforeExecute,这可能会引发异常,在这种情况下,我们会导致线程死亡(以 completeA 突然为 true 中断循环)而不处理任务。
- 假设 beforeExecute 正常完成,我们运行任务,收集其抛出的任何异常以发送到 afterExecute。我们分别处理 RuntimeException、Error(规范保证我们捕获这两个错误)和任意 Throwable。因为我们无法在 Runnable.run 中重新抛出 Throwable,所以我们在出路时将它们包装在 Errors 中(到线程的 UncaughtExceptionHandler)。任何抛出的异常也保守地导致线程死亡。
- task.run 完成后,我们调用 afterExecute,这也可能会抛出异常,这也会导致线程死亡。根据 JLS Sec 14.20,即使 task.run 抛出,此异常也会生效。异常机制的净效果是,afterExecute 和线程的 UncaughtExceptionHandler 具有尽可能准确的信息,我们可以提供有关用户代码遇到的任何问题的信息。

当我们发送http://localhost:8081/user/test请求时,步入这个task.run()方法中:

步入doRun方法中:

…
…
…
最终经过数十个调用,会在一个filterChanin链中调用servlet.service(request, response)方法:

然后会判断当前请求中的方法是否包含规定的方法:HTTP_SERVLET_METHODS.contains(request.getMethod())

然后会调用doGet方法:

之后调用经典的doService方法:

步入doService方法之后,又会调用doDispatch方法:

看一看这个核心方法:doDispatch。

protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {...try {...try {// 检查是否文件请求processedRequest = checkMultipart(request);...// 根据请求找到对应的控制器执行器链HandlerExecutionChain mappedHandler = getHandler(processedRequest);...// 找到对应控制器的适配器,用来执行操作的HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());...// 执行拦截器前置if (!mappedHandler.applyPreHandle(processedRequest, response)) {return;}// 真正执行控制器逻辑mv = ha.handle(processedRequest, response, mappedHandler.getHandler());...// 执行拦截器后置mappedHandler.applyPostHandle(processedRequest, response, mv);}...// 处理返回结果processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);}...
}
先看checkMultipart(request)方法,它是用来检查是否是文件上传,如果有文件上传,则将request包装成StandardMultipartHttpServletRequest
关于mappedHandler = getHandler(processedRequest);和HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());这两个方法,和前面AOP讲到的获取拦截器和适配器的逻辑差不多,循环去匹配,这里就不展开了。
重点看一下mv = ha.handle(processedRequest, response, mappedHandler.getHandler());这个真正执行控制器逻辑的方法。
步入handle方法:最终来到这:

步入invokeHandlerMethod方法:
首先创建ServletInvocableHandlerMethod对象,再去调用。

步入invokeAndHandle方法:
首先去执行控制器的逻辑,如果有结果再去处理结果。

看看如何执行控制器的逻辑的,步入invokeForRequest方法:
首先获取方法参数,再去invoke:
如何实现的就不看了吧,最后肯定是调用本地方法去执行控制器的逻辑。
感兴趣可以翻一翻我的博客,有一篇是如何解析本地方法的。可以看看cpp是如何实现的。

最后,我们能得到返回的结果:

最后会去调用这行代码:
this.returnValueHandlers.handleReturnValue(returnValue, getReturnValueType(returnValue), mavContainer, webRequest);
步入handleReturnValue方法:

步入handleReturnValue方法:

步入writeWithMessageConverters方法:
最后经过层层包装,调用((HttpMessageConverter) converter).write(body, selectedMediaType, outputMessage);方法:

步入write方法:

步入writeInternal方法:

步入copy方法:
落叶归根,结束。

其实关于SpringMVC还有很多没写,但是首先知道这个流程就基本够用了,之后用到哪些的哪些的时候,再按着这个流程看就好。
值得一提的是我们这个demo没有文件,也没有参数,所以撸流程还是很容易的,如果有参数还要注意是如何解析参数的,如果用@RequestParam注解的话,直接通过反射就可以获取到,Spring也提供了处理这个注解的解析器,如果不加注解,会默认使用名称绑定,底层用asm框架读取字节码来获取参数名称,所以编码记得用@RequestParam声明参数,之后会放进一个缓存数组中,在ServletInvocableHandlerMethod invocableMethod = createInvocableHandlerMethod(handlerMethod);代码执行时,就会封装成ServletInvocableHandlerMethod 对象。
其他的暂且先不提了,都比较简单,点点看看就行了。
相关文章:
【Spring6源码・MVC】请求处理流程源码解析
上一篇《【Spring6源码・MVC】初始化registry,完成url和controller的映射关系》我们知道,在IOC容器加载的同时,初始化了registry这个HashMap,这个HashMap中存放了请求路径和对应的方法。当我们请求进来,会通过这个regi…...
elasticsearch term match 查询
1. 准备数据 PUT h1/doc/1 {"name": "rose","gender": "female","age": 18,"tags": ["白", "漂亮", "高"] }PUT h1/doc/2 {"name": "lila","gender&quo…...
canal使用说明:MySQL、Redis实时数据同步
1. canal简介 canal是阿里开源的数据同步工具,基于bin log可以将数据库同步到其他各类数据库中,目标数据库支持mysql,postgresql,oracle,redis,MQ,ES等 canal分成服务端deployer和客户端adapter,我们可以部署多个,同时为了方便管…...
计算机视觉框架OpenMMLab开源学习(三):图像分类实战
前言:本篇主要偏向图像分类实战部分,使用MMclassification工具进行代码应用,最后对水果分类进行实战演示,本次环境和代码配置部分省略,具体内容建议参考前一篇文章:计算机视觉框架OpenMMLab开源学习&#x…...
awk命令
一.介绍 awk是专门为文本处理设计的编程语言,是一门数据驱动的编程语言。与sed类似,都是以数据驱动的行处理软件,主要用于数据扫描,过滤和汇总。数据可以来自于标准输入,管道或者文件。 二.语法 awk是一种处理文本文件…...
LocalDateTime获取时间的年、月、日、时、分、秒、纳秒
如何把String/Date转成LocalDateTime参考String、Date与LocalDate、LocalTime、LocalDateTime之间互转 String、Date、LocalDateTime、Calendar与时间戳之间互相转化参考String、Date、LocalDateTime、Calendar与时间戳之间互相转化 方法介绍 getYear() 获取日期的年 getMon…...
MoveIT Rviz和Gazebo联合仿真
文章目录环境安装概述ros_control框架ros_control数据流文件配置附加工具故障问题解决参考接前两篇:ROS MoveIT1(Noetic)安装总结 Solidworks导出为URDF用于MoveIT总结(带prismatic) MoveIT1 Assistant 总结 环境 Ubu…...
ESP32S2(12K)-DS18B20数码管显示温度
一、物料清单: NODEMCU-32-S2 (ESP32-12K)四段数码管(共阴)DS18B20(VCC/DQ/GND)Arduino-IDE 2.0.3二、实现方法及效果图: 2.1 引用库 // #include <OneWire.h> //可以不引入,因为DallasTemperature.h中已经引入了OneWire.h #include <DallasTemperature.h>#…...
linux栈溢出定位
一、编译选项定位堆栈溢出 来源:堆栈溢出检测机制 - SkrSky - 博客园 1、栈溢出可能打印 unhandled level 1 translation fault (11) at 0x7f8d0347, esr 0x92000005 2、栈溢出保护机制 gcc提供了栈保护机制stack-protector(编译选项-fstack-protec…...
CSS基础:选择器和声明样式
CSS概念 CSS(Cascading Style Sheets)层叠样式表,又叫级联样式表,简称样式表 CSS用于HTML文档中元素样式的定义 使用css让网页具有美观一致的页面 语法 CSS 规则由两个主要的部分构成:选择器和声明样式 选择器通常…...
VS中安装gismo库
文章目录前言一、下载安装paraview直接下载压缩包安装就可以了解压后按步骤安装即可二、gismo库的安装gismo库网址第一种方法:第二种方法第三种方法:用Cmake软件直接安装首先下载cmake软件[网址](https://cmake.org/download/)安装gismo库三、gismo库的使…...
元学习方法解决CDFSL以及两篇SOTA论文讲解
来源:投稿 作者:橡皮 编辑:学姐 带你学习跨域小样本系列1-简介篇 跨域小样本系列2-常用数据集与任务设定详解 跨域小样本系列3:元学习方法解决CDFSL以及两篇SOTA论文讲解(本篇) 跨域小样本系列4…...
大数据之------------数据中台
一、什么是数据中台 **数据中台是指通过数据技术,对海量数据进行采集、计算、存储、加工,同时统一标准和口径。**数据中台的目标是让数据持续用起来,通过数据中台提供的工具、方法和运行机制,把数据变为一种服务能力,…...
Python 中 字符串是什么?
字符串是 Python 中最常用的数据类型。我们可以使用引号 ( ’ 或 " ) 来创建字符串。 创建字符串很简单,只要为变量分配一个值即可。例如: var1 ‘Hello World!’ var2 “Python Runoob” Python 访问字符串中的值 Python 不支持单字符类型&…...
OJ刷题Day1 · 一维数组的动态和 · 将数字变成 0 的操作次数 · 最富有的客户资产总量 · Fizz Buzz · 链表的中间结点 · 赎金信
一、一维数组的动态和二、将数字变成 0 的操作次数三、最富有的客户资产总量四、Fizz Buzz五、链表的中间结点六、赎金信一、一维数组的动态和 给你一个数组 nums 。数组「动态和」的计算公式为:runningSum[i] sum(nums[0]…nums[i]) 。 请返回 nums 的动态和。 示…...
【数据结构】栈——必做题
逆波兰表达式后缀表达式的出现是为了方便计算机处理,它的运算符是按照一定的顺序出现,所以求值过程中并不需要使用括号来指定运算顺序,也不需要考虑运算符号(比如加减乘除)的优先级。先介绍中简单的人工转化方法&#…...
LearnOpenGL 笔记 - 入门 04 你好,三角形
系列文章目录 LearnOpenGL 笔记 - 入门 01 OpenGLLearnOpenGL 笔记 - 入门 02 创建窗口LearnOpenGL 笔记 - 入门 03 你好,窗口 文章目录系列文章目录前言你好,三角形顶点输入顶点着色器(Vertex Shader)编译着色器片段着色器&…...
keepalived+mysql高可用
一.设置mysql同步信息两节点安装msyql略#配置节点11.配置权限允许远程访问mysql -u root -p grant all on *.* to root% identified by Root1212# with grant option; flush privileges;2.修改my.cnf#作为主节点配置(节点1)#作为主节点配置 server-id 1 …...
JAVA工具篇--1 Idea中 Gradle的使用
前言: 既然我们已经使用Maven 来完成对项目的构建,为什么还要使用Gradle 进行项目的构建;gradle和maven都可以作为java程序的构建工具,但两者还是有很大的不同之处的:1.可扩展性,gradle比较灵活,…...
弄懂自定义 Hooks 不难,改变开发认知有点不习惯
前言 我之前总结逻辑重用的时候,就一直在思考一个问题。 对于逻辑复用,render props 和 高阶组件都可以实现,同样官方说 Hooks 也可以实现,且还是在不增加额外的组件的情况下。 但是我在项目代码中,没有找到自定义 …...
如何快速实现本地离线语音识别:面向Windows用户的完整解决方案
如何快速实现本地离线语音识别:面向Windows用户的完整解决方案 【免费下载链接】TMSpeech 腾讯会议摸鱼工具 项目地址: https://gitcode.com/gh_mirrors/tm/TMSpeech 还在为会议记录、视频字幕、语音笔记而烦恼吗?传统的语音识别工具要么需要网络…...
Hunyuan-MT-7B在Win11系统下的高效部署与性能调优
Hunyuan-MT-7B在Win11系统下的高效部署与性能调优 最近腾讯开源的Hunyuan-MT-7B翻译模型挺火的,70亿参数就拿下了WMT2025比赛里31个语种中的30个第一,支持33种语言互译,包括一些少数民族语言和方言。性能这么强,很多朋友都想在本…...
Coda Prompt 实战:如何通过智能提示提升开发效率
作为一名开发者,每天面对海量代码,你是否也常常感到疲惫?重复的 CRUD 操作、频繁在文档和 IDE 之间切换、为某个函数命名绞尽脑汁……这些看似微小的“摩擦力”,日积月累却严重消耗着我们的精力与时间。今天,我想和大家…...
ThinkPad双风扇深度解析:TPFanCtrl2实战配置与性能优化指南
ThinkPad双风扇深度解析:TPFanCtrl2实战配置与性能优化指南 【免费下载链接】TPFanCtrl2 ThinkPad Fan Control 2 (Dual Fan) for Windows 10 and 11 项目地址: https://gitcode.com/gh_mirrors/tp/TPFanCtrl2 TPFanCtrl2是一款专为ThinkPad双风扇机型设计的…...
HunyuanVideo-Foley惊艳效果:AI生成的赛博朋克城市雨夜环境音效
HunyuanVideo-Foley惊艳效果:AI生成的赛博朋克城市雨夜环境音效 1. 效果展示:赛博朋克音效的沉浸式体验 HunyuanVideo-Foley 私有部署镜像带来的音效生成能力,让AI创作达到了专业音频工程师的水准。我们以"赛博朋克城市雨夜"为场…...
文档权限验证API:ONLYOFFICE Docs检查用户访问权限的完整指南
文档权限验证API:ONLYOFFICE Docs检查用户访问权限的完整指南 【免费下载链接】DocumentServer ONLYOFFICE Docs is a free collaborative online office suite comprising viewers and editors for texts, spreadsheets and presentations, forms and PDF, fully c…...
[搭建Web漏洞靶场:DVWA在CentOS上的部署]
//DVWA 是一个用来进行安全脆弱性鉴定的Web应用平台,可以手动调整靶机源代码的安全级别,包含暴力破解、命令行注入、跨站请求伪造、文件包含、文件上传、SQL注入、XSS等漏洞。(1)下载安装包通过网盘分享的文件:DVWA-ma…...
LED点阵驱动库LEDMatrix:嵌入式硬件时序控制实战指南
1. LEDMatrix 库概述:面向硬件驱动的二维点阵控制框架LEDMatrix 是一个专为嵌入式系统设计的轻量级 C 语言库,核心目标是将抽象的二维布尔数组(bool matrix[rows][cols])高效、可靠地映射至物理 LED 点阵屏。其设计哲学并非通用图…...
Virtual-Display-Driver技术指南:Windows虚拟显示驱动解决方案
Virtual-Display-Driver技术指南:Windows虚拟显示驱动解决方案 【免费下载链接】Virtual-Display-Driver Add virtual monitors to your windows 10/11 device! Works with VR, OBS, Sunshine, and/or any desktop sharing software. 项目地址: https://gitcode.c…...
新概念英语第一册083_Going on holiday
Lesson 83: Going on holiday Watch the story and answer the question Where did Sam go for his holiday this year? He stayed at home.Key words and expressions mess n. 杂乱,pack v. 包装,打包,装箱suitcase …...
