SpringMVC源码深度解析(下)

        接着上一遍博客《SpringMVC源码深度解析(中)》继续聊。上一篇博客中,返回的是对象的情况下SpringMVC框架会怎么处理,这种情况也是现在用得最多的,因为都是前后端分离。如果返回的是ModelAndView,则是另外的处理逻辑了,主要看ModelAndViewMethodReturnValueHandler对象,代码如下:

        到这里位置,视图的解析渲染就讲完了,回到DispatcherServlet#processDispatchResult()方法,代码如下:

        该注解可以添加到类/方法上,最终会注解中设置的异常原因和状态码设置到响应中。回到DispatcherServlet#processDispatchResult()方法,再看看这里:

       再回到DispatcherServlet#processDispatchResult()方法被调用的地方。 由上面的代码可知:如果有异常,但是没有配置异常处理解析器或者异常解析处理器返回的视图为空的话,异常会继续往外抛,由于最外层还有一个try/catch,最终会调用DispatcherServlet#triggerAfterCompletion()方法,代码如下:

        到这里为止,DispatcherServlet的流程大概讲完了。当然地方也没有讲到,有兴趣的朋友可以自行研究,起码我觉得了解到这个程度,在日常开发中应该是完全够用了。接下来我会讲一下流程中没有讲到的东西,比较零散,讲到哪里是哪里,望理解。

        第一个想到的就是 @EnableWebMvc注解,它的作用是什么呢?先看看这个注解:

        看到了@Import注解,马上就能想到,这是Spring框架的扩展点之一,该注解中的类会被放入Spring容器中。看看该类,代码如下:

package org.springframework.web.servlet.config.annotation;import java.util.List;import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.format.FormatterRegistry;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.lang.Nullable;
import org.springframework.util.CollectionUtils;
import org.springframework.validation.MessageCodesResolver;
import org.springframework.validation.Validator;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.method.support.HandlerMethodReturnValueHandler;
import org.springframework.web.servlet.HandlerExceptionResolver;/*** A subclass of {@code WebMvcConfigurationSupport} that detects and delegates* to all beans of type {@link WebMvcConfigurer} allowing them to customize the* configuration provided by {@code WebMvcConfigurationSupport}. This is the* class actually imported by {@link EnableWebMvc @EnableWebMvc}.** @author Rossen Stoyanchev* @since 3.1*/
@Configuration(proxyBeanMethods = false)
public class DelegatingWebMvcConfiguration extends WebMvcConfigurationSupport {private final WebMvcConfigurerComposite configurers = new WebMvcConfigurerComposite();@Autowired(required = false)public void setConfigurers(List<WebMvcConfigurer> configurers) {if (!CollectionUtils.isEmpty(configurers)) {this.configurers.addWebMvcConfigurers(configurers);}}@Overrideprotected void configurePathMatch(PathMatchConfigurer configurer) {this.configurers.configurePathMatch(configurer);}@Overrideprotected void configureContentNegotiation(ContentNegotiationConfigurer configurer) {this.configurers.configureContentNegotiation(configurer);}@Overrideprotected void configureAsyncSupport(AsyncSupportConfigurer configurer) {this.configurers.configureAsyncSupport(configurer);}@Overrideprotected void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {this.configurers.configureDefaultServletHandling(configurer);}@Overrideprotected void addFormatters(FormatterRegistry registry) {this.configurers.addFormatters(registry);}@Overrideprotected void addInterceptors(InterceptorRegistry registry) {this.configurers.addInterceptors(registry);}@Overrideprotected void addResourceHandlers(ResourceHandlerRegistry registry) {this.configurers.addResourceHandlers(registry);}@Overrideprotected void addCorsMappings(CorsRegistry registry) {this.configurers.addCorsMappings(registry);}@Overrideprotected void addViewControllers(ViewControllerRegistry registry) {this.configurers.addViewControllers(registry);}@Overrideprotected void configureViewResolvers(ViewResolverRegistry registry) {this.configurers.configureViewResolvers(registry);}@Overrideprotected void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) {this.configurers.addArgumentResolvers(argumentResolvers);}@Overrideprotected void addReturnValueHandlers(List<HandlerMethodReturnValueHandler> returnValueHandlers) {this.configurers.addReturnValueHandlers(returnValueHandlers);}@Overrideprotected void configureMessageConverters(List<HttpMessageConverter<?>> converters) {this.configurers.configureMessageConverters(converters);}@Overrideprotected void extendMessageConverters(List<HttpMessageConverter<?>> converters) {this.configurers.extendMessageConverters(converters);}@Overrideprotected void configureHandlerExceptionResolvers(List<HandlerExceptionResolver> exceptionResolvers) {this.configurers.configureHandlerExceptionResolvers(exceptionResolvers);}@Overrideprotected void extendHandlerExceptionResolvers(List<HandlerExceptionResolver> exceptionResolvers) {this.configurers.extendHandlerExceptionResolvers(exceptionResolvers);}@Override@Nullableprotected Validator getValidator() {return this.configurers.getValidator();}@Override@Nullableprotected MessageCodesResolver getMessageCodesResolver() {return this.configurers.getMessageCodesResolver();}}

        有很多实现方法,逻辑类似,如DelegatingWebMvcConfiguration#addArgumentResolvers()方法为例:

        看到上面的这段代码就可以知道:从Spring容器中获取到的WebMvcConfigurer对象的集合,并调用DelegatingWebMvcConfiguration#addArgumentResolvers(),即遍历WebMvcConfigurer对象的集合,将设置的HandlerMethodArgumentResolver的集合设置给WebMvcConfigurer对象。

        当然,除了设置HandlerMethodArgumentResolver外,还可以设置HttpMessageConverter、HandlerMethodReturnValueHandler、InterceptorRegistry、CorsRegistry、HandlerExceptionResolver 等等。由于DelegatingWebMvcConfiguration类还是被@Configuration注解所修饰,因此它还是个配置类,配置相关都在它的父类中,即WebMvcConfigurationSupport,看看这个类,截取部分代码如下:

        这是添加拦截器的逻辑,因此可以知道,除了添加@EnableWebMvc注解外,还需要定义一个WebMvcConfigurer接口的实现了,并将其注册到Spring容器中。以添加拦截器为例:实现了WebMvcConfigurer接口,需要实现WebMvcConfigurer#addInterceptors()方法,入参为InterceptorRegistry,将自定义的拦截器添加到传入的 InterceptorRegistry对象中。在DelegatingWebMvcConfiguration类中,会获取到Spring容器中WebMvcConfigurer对象的集合。在WebMvcConfigurationSupport中,比如创建HandlerMapping对象的时候,就会调用到WebMvcConfigurationSupport#getInterceptors()方法,进而调用到DelegatingWebMvcConfiguration#addInterceptors()方法,传入InterceptorRegistry对象,实际上就是进行拦截器的设置,最终会将自定义的拦截器设置到InterceptorRegistry对象中。

        如果是设置其他的对象,如HandlerMethodArgumentResolver、HttpMessageConverter、CorsRegistry、HandlerMethodReturnValueHandler,是同样的原理。对于HttpMessageConverter而言,有点不同,看看代码:

        到这里为止,@EnableWebMvc注解的原理讲完了。再看看@ControllerAdvice注解,这是示例,代码如下:

        一般@ControllerAdvice和@ExceptionHandler注解是配合使用的,想知道原理,线看看注解,代码如下:

        对于这个注解是怎么生效的,还是需要先回到WebMvcConfigurationSupport中,由于是跟异常相关,因此肯有可能看HandlerExceptionResolver类,看看WebMvcConfigurationSupport中哪里有配置HandlerExceptionResolver类,搜的时候也确实搜到了,代码如下:

        看看 ExceptionHandlerExceptionResolver类,同样只截取核心的代码:

        发现ExceptionHandlerExceptionResolver实现了InitializingBean,当然需要看看ExceptionHandlerExceptionResolver#afterPropertiesSet()方法,代码如下:

        通过ControllerAdviceBean#findAnnotatedBeans()方法,可以获取ControllerAdviceBean对象的集合(被@ControllerAdvice修饰的Class被封装成该类),遍历,获取到beanType,也就是被@ControllerAdvice修饰的Class,创建ExceptionHandlerMethodResolver对象,调用它的有参构造,传入beanType,看看ExceptionHandlerMethodResolver类,代码如下:

        到这里为止,ExceptionHandlerExceptionResolver的exceptionHandlerAdviceCache属性,已经不为空了,缓存的是ExceptionHandlerMethodResolver对象,而ExceptionHandlerMethodResolver对象的mappedMethods属性,缓存的才是我们想要的,key为异常类型,value为被@ExceptionHandler注解修饰的方法。

        再想想会在哪里使用呢?由于是报错,前面我讲到的DispatcherServlet流程中,一定会进到某个方法,先看看那块的代码:

        可知,前面通过try/catch捕获到异常,并调用DispatcherServlet#processDispatchResult()方法进行处理的时候,传入异常对象dispatchException,再点进这个方法看看:

        看看ExceptionHandlerExceptionResolver#getExceptionHandlerMethod()方法,代码如下:

再看看ServletInvocableHandlerMethod#invokeAndHandle()方法,代码如下:

        到这里为止,@ControllerAdvice和@ExceptionHandler注解的原理讲完了。

        SpringMVC框架,到这里也算是讲完了,可能有一些遗漏。如果对SpringMVC框架中,有些我没讲到的地方还有疑问,欢迎留言,谢谢!

        

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/48080.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

稀疏支持向量机(Sparse Support Vector Machine, Sparse SVM)

稀疏支持向量机&#xff08;Sparse Support Vector Machine, Sparse SVM&#xff09; 稀疏支持向量机是一种在支持向量机的基础上&#xff0c;通过引入稀疏性约束&#xff0c;使得模型参数更加稀疏&#xff0c;从而提高模型的可解释性和计算效率的方法。以下是稀疏支持向量机的…

Ideal窗口中左右侧栏消失了

不知道大家在工作过程中有没有遇到过此类问题&#xff0c;不论是Maven项目还是Gradle项目&#xff0c;突然发现Ideal窗口右侧图标丢失了&#xff0c;同事今天突然说大象图标不见了&#xff0c;不知道怎样刷新gradle。 不要慌张&#xff0c;下面提供一些解决思路&#xff1a; 1…

LeetCode 232.用栈实现队列 C写法

LeetCode 232.用栈实现队列 C写法 思路&#x1f9d0;&#xff1a; 栈代码在本篇中。与队列实现栈类似&#xff0c;不过这里我们建立两个栈&#xff0c;一个栈专门存放入队数据&#xff0c;一个专门存放出队数据&#xff0c;不需要再来回导数据。原理在于一个栈的数据到另一个栈…

Windows右键新建Markdown文件类型配置 | Typora | VSCode

&#x1f64b;大家好&#xff01;我是毛毛张! &#x1f308;个人首页&#xff1a; 神马都会亿点点的毛毛张 今天毛毛张分享的是如何在右键的新建菜单中添加新建MarkdownFile文件&#xff0c;这是毛毛张分享的关于Typora软件的相关知识的第三期 文章目录 1.前言&#x1f3dd;…

「MQTT over QUIC」与「MQTT over TCP」与 「TCP 」通信测试报告

一、结论 在实车5G测试中「MQTT Over QUIC」整体表现优于「TCP」&#xff0c;可在系统架构升级时采用MQTT Over QUIC替换原有的TCP通讯&#xff1b;从实现原理上基于QUIC比基于TCP在弱网、网络抖动导致频繁重连场景延迟更低。 二、测试方案 网络类型&#xff1a;实车5G、实车…

Easysearch、Elasticsearch、Amazon OpenSearch 快照兼容对比

启动集群 Easysearch sysctl -w vm.max_map_count262144Amazon OpenSearch Elasticsearch 由于这个docker compose没有关于kibana的配置&#xff0c;所以我们还是用Console添加原生的Elasticsearch集群 集群信息 快照还原的步骤 快照前的准备 插件安装 本次测试选择把索…

生产力工具|Endnote 21 Macwin版本安装

一、软件下载&#xff1a; &#xff08;一&#xff09;mac版本 Endnote 21版本下载&#xff1a;点击下载 Endnote 20版本下载&#xff1a;点击下载 Endnote X9版本下载&#xff1a;点击下载 &#xff08;二&#xff09;Endnote 20 Win版本 第一步&#xff1a;安装好官网软…

【技术前沿 | AI Native应用新纪元:深度解析模型微调的艺术】

在这个智能化浪潮席卷全球的今天&#xff0c;AI技术已经不再是遥不可及的未来概念&#xff0c;而是深深地融入了我们的日常生活与工作中。从智能家居到自动驾驶&#xff0c;从智能客服到医疗诊断&#xff0c;AI正以它独有的方式改变着世界。而在这一过程中&#xff0c;AI Nativ…

随手记:推荐vscode好用的几个小插件

原始用了挺久的插件&#xff0c;先上截图&#xff0c;以后有空再编辑&#xff1a; fittenCode 是一个AI小助手&#xff0c;相对来说很智能&#xff0c;你在vscode当中编写代码&#xff0c;甚至都可以知道你下一步知道干嘛&#xff0c;训练的还可以。而且还可以帮你起名字&…

2024年7月17日(nodejs,npm设置国内镜像,vue脚手架,远程管理ssh,踢出用户,scp命令,ssh免密登录)

1、安装nodejs服务 nodejs是一个运行1环境&#xff0c;和javajdk运行环境格式一样 [roota ~]# yum -y install nodejs.x86_64 安装完成之后&#xff0c;使用node -v 查看版本 [roota ~]# node -v v16.20.2 2、简易服务器的环境安装npm 安装包管理器 npm node packae manger [ro…

云计算实训09——rsync远程同步、自动化推取文件、对rsyncd服务进行加密操作、远程监控脚本

一、rsync远程同步 1.rsync基本概述 &#xff08;1&#xff09;sync同步 &#xff08;2&#xff09;async异步 &#xff08;3&#xff09;rsync远程同步 2.rsync的特点 可以镜像保存整个目录树和文件系统 可以保留原有权限&#xff0c;owner,group,时间&#xff0c;软硬链…

数据分析入门:用Python和Numpy探索音乐流行趋势

一、引言 音乐是文化的重要组成部分&#xff0c;而音乐流行趋势则反映了社会文化的变迁和人们审美的变化。通过分析音乐榜单&#xff0c;我们可以了解哪些歌曲或歌手正在受到大众的欢迎&#xff0c;甚至预测未来的流行趋势。Python作为一种强大的编程语言&#xff0c;结合其丰…

[数据集][目标检测]导盲犬拐杖检测数据集VOC+YOLO格式4635张2类别

数据集格式&#xff1a;Pascal VOC格式YOLO格式(不包含分割路径的txt文件&#xff0c;仅仅包含jpg图片以及对应的VOC格式xml文件和yolo格式txt文件) 图片数量(jpg文件个数)&#xff1a;4635 标注数量(xml文件个数)&#xff1a;4635 标注数量(txt文件个数)&#xff1a;4635 标注…

RabbitMQ学习实践一:MQ的安装

文章是本人在学习springboot实现消息队列功能时所经历的过程的记录&#xff0c;仅供参考&#xff0c;如有侵权请随时指出。 参考文章地址&#xff1a; RabbitMQ安装与入门_rabbitmq win11配置-CSDN博客 RabbitMQ入门到实战一篇文章就够了-CSDN博客 RabbitMQ系列&#xff08…

【LeetCode】十五、回溯法:括号生成 + 子集

文章目录 1、回溯法2、leetcode22&#xff1a;括号生成3、leetcode78&#xff1a;子集 1、回溯法 使用场景&#xff0c;如找[1&#xff0c;2&#xff0c;3]的所有子集&#xff1a; 2、leetcode22&#xff1a;括号生成 以n2为例&#xff0c;即两个左括号、两个右括号&#xff0c…

汇编实验5

本实验在32位Linux虚拟机中完成&#xff08;点击查看安装教程&#xff09; 实验内容 二进制炸弹实际是由C语言源程序生成的可执行目标代码&#xff0c;主程序可参考bomb.c。运行时&#xff0c;会按次序提示用户输入3个不同的字符串。如果输入的字符串有误&#xff0c;炸弹就会…

随手记:vsCode修改主题色为自定义颜色

因为工作需要长时间面对vscode&#xff0c;视力不好&#xff0c;想要把工具改成护眼色&#xff0c;于是就把vscode改成了自定义的护眼色 效果图&#xff1a; 操作步骤&#xff1a; 快捷键打开设置页面&#xff1a; 按住ctrlshiftp 选择Open setting 按回车键 打开setting页面编…

FlagEval 7月榜丨新增29个模型评测结果,智源发布评估技术报告《AI大模型能力全景扫描》

智源研究院FlagEval 7月榜单新增29个语言、多模态和文生图开源与闭源模型评测结果&#xff0c;包括阿里巴巴、OpenAI、快手、智谱等厂商近期发布的新模型。 本次评测发现&#xff0c;大语言模型&#xff0c;国产模型主观能力整体有所提升&#xff1b;视觉语言新模型的能力有所…

AI(Adobe lliustrator)教程+软件包

简介&#xff1a; 软件主要应用于印刷出版、海报书籍排版、专业插画、多媒体图像处理和互联网页面的制作等&#xff0c;也可以为线稿提供较高的精度和控制&#xff0c;适合生产任何小型设计到大型的复杂项目。 通常用于创建LOGO(商标或徽标)&#xff0c;图标&#xff0c;插图…

【数据结构】线性结构——数组、链表、栈和队列

目录 前言 一、数组&#xff08;Array&#xff09; 1.1优点 1.2缺点 1.3适用场景 二、链表&#xff08;Linked List&#xff09; 2.1优点 2.2缺点 2.3适用场景 三、栈&#xff08;Stack&#xff09; 3.1优点 3.2缺点 3.3适用场景 四、队列&#xff08;Queue&#xff09; 4.1优点…