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;从而提高模型的可解释性和计算效率的方法。以下是稀疏支持向量机的…

CSS3 教程

CSS3 教程 引言 CSS3&#xff0c;即层叠样式表的第三代&#xff0c;是网页设计和开发中不可或缺的技术之一。它为HTML元素提供了丰富的样式定义&#xff0c;使得网页不仅内容丰富&#xff0c;而且外观美观、交互性强。本教程将详细介绍CSS3的基础知识、高级特性以及最佳实践&…

【Spring Boot 中的 `banner.txt` 和 `logback-spring.xml` 配置】

文章目录 一、banner.txt1. 创建自定义 banner.txt2. 配置 banner.txt 的内容 二、logback-spring.xml1. 创建 logback-spring.xml2. 配置 logback-spring.xml 一、banner.txt banner.txt 是 Spring Boot 项目启动时显示的自定义横幅内容。用来展示项目名称、版本信息或者其他…

python实现计数排序、桶排序和基数排序算法

python实现计数排序、桶排序和基数排序算法 计数排序算法步骤&#xff1a; Python实现计数排序桶排序算法步骤&#xff1a; Python实现桶排序基数排序算法步骤&#xff1a; Python实现基数排序算法时间复杂度 计数排序 计数排序是一种非比较排序算法&#xff0c;适用于元素范围…

数据仓库中事实表设计的关键步骤解析

在数据仓库的设计过程中&#xff0c;事实表是描述业务度量的核心组件。本文将深入探讨数据仓库中事实表设计的关键步骤&#xff0c;包括选择业务过程及确定事实表类型、声明粒度、确定维度和确定事实的过程&#xff0c;帮助读者更好地理解和应用事实表设计的原则和方法。 第一…

Ideal窗口中左右侧栏消失了

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

【C语言ffmpeg】打开第一个视频

文章目录 前言须知ffmpeg打开文件基本流程图ffmpeg打开媒体文件AVFormatContext *avformat_alloc_context(void);AVFormatContext 成员变量及其作用AVInputFormat *iformatAVOutputFormat *oformatvoid *priv_dataAVIOContext *pbunsigned int nb_streamsAVStream **streamscha…

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集群 集群信息 快照还原的步骤 快照前的准备 插件安装 本次测试选择把索…

【微服务】feign使用

【微服务】feign使用 引入依赖启动类配置注解创建业务层使用项目调用可能会遇到的bug 01 引入依赖 Feign是Spring Cloud提供的一个声明式的伪Http客户端&#xff0c; 它使得调用远程服务就像调用本地服务一样简单&#xff0c; 只需要创建一个接口并添加一个注解即可。在需要…

解决echarts在uniapp里tooltip,legend不能点击的问题

在main.js文件里面添加&#xff0c;这样tooltip就可以点击&#xff0c;但是legend可能还不能点击&#xff0c; window.wx {} // 在使用获取echarts dom使用 echarts.env.touchEventsSupported false; echarts.env.wxa false; const chartContainer this.$refs.chartContai…

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

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

Eureka: 微服务架构中的服务发现与注册实践

Eureka介绍与使用教程 你好&#xff0c;我是悦创。 Eureka 是 Netflix 开发的一款服务发现&#xff08;Service Discovery&#xff09;工具&#xff0c;它主要用于云中基于微服务架构的应用程序。Eureka使服务实例能够动态地注册自己&#xff0c;而其他服务实例可以通过 Eure…

【技术前沿 | 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;结合其丰…