【SpringMVC源码三千问】DispatcherServlet源码解析

news/2024/10/18 5:44:09/

DispatcherServlet#doDispatch() 是 SpringMVC 处理请求分发的方法,只要是 spring mvc 处理的 http 请求,都会经过 DispatcherServlet 的请求分发处理,从而调用相应的 handler method。

DispatcherServlet#doDispatch() 源码分析:

DispatcherServlet.png

可以看到,DispatcherServlet#doDispatch() 的处理大体分了 6 步:
1、获取 request 对应的 HandlerExecutionChain(它包含 handler 和 interceptors)
2、获取 handler 对应的 HandlerAdapter
3、执行 handler 的前置处理: HandlerInterceptor#preHandle()
4、通过 HandlerAdapter#handler() 来执行处理程序
5、执行 handler 的后置处理:HandlerInterceptor#postHandle()
6、对返回值进行处理(包括正常返回 和 异常处理)

处理程序 handler 始终包装在 HandlerExecutionChain 实例中,HandlerExecutionChain 中可以附带一些 HandlerInterceptor
DispatcherServlet 将首先按给定顺序调用每个 HandlerInterceptor#preHandle() 方法,如果所有 preHandle 都返回 true 的话,才会调用处理程序 handler 本身。

所以,如果我们想要找 url 与 handler method 的映射关系的话,就可以从 DispatcherServlet#getHandler() 来入手,打个断点调试。

HandlerExecutionChain 的获取 和 组装

HandlerExecutionChain 是 handler 的执行链,它是由 handler 和 interceptors 组成的。

HandlerExecutionChain 是通过 DispatcherServlet#getHandler() 来获取的:

/*** 将所有的 HandlerMapping 按顺序遍历一次,获取 request 对应的 HandlerExecutionChain。*/
@Nullable
protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {if (this.handlerMappings != null) {for (HandlerMapping mapping : this.handlerMappings) {HandlerExecutionChain handler = mapping.getHandler(request);if (handler != null) {return handler;}}}return null;
}

可以看到,在获取 HandlerExecutionChain 时,Spring 会将所有的 HandlerMapping 按顺序遍历一次。
而在 Spring 中有许多 HandlerMapping,最常用的当属 RequestMappingHandlerMapping

HandlerExecutionChain 的获取

HandlerExecutionChain 的获取是在 AbstractHandlerMapping#getHandler() 中完成的。
主要分成了两步:
1、获取 request 对应的 handler 程序
2、将 handler 和 相应的 HandlerInterceptors 组装成 HandlerExecutionChain

getHandler.png

AbstractHandlerMapping#getHandler() 中包含了对 cors 的处理,具体是往 HandlerExecutionChain 中添加了 CorsInterceptor。
@see AbstractHandlerMapping#getCorsHandlerExecutionChain()

HandlerExecutionChain 的构造和组装过程

HandlerExecutionChain 的构造组装是在 AbstractHandlerMapping#getHandlerExecutionChain()

/*** 为给定的 handler 构建 HandlerExecutionChain(包含 handler 和 HandlerInterceptor)。*/
protected HandlerExecutionChain getHandlerExecutionChain(Object handler, HttpServletRequest request) {// 1、根据 handler 构造 HandlerExecutionChain  HandlerExecutionChain chain = (handler instanceof HandlerExecutionChain ?(HandlerExecutionChain) handler : new HandlerExecutionChain(handler));// 2、给 HandlerExecutionChain 添加 HandlerInterceptor  for (HandlerInterceptor interceptor : this.adaptedInterceptors) {if (interceptor instanceof MappedInterceptor) {MappedInterceptor mappedInterceptor = (MappedInterceptor) interceptor;if (mappedInterceptor.matches(request)) {chain.addInterceptor(mappedInterceptor.getInterceptor());}} else {chain.addInterceptor(interceptor);}}return chain;
}

DispatcherServlet 中使用的默认策略接口

DispatcherServlet.properties 中指定了 DispatcherServlet.java 中使用的一些策略接口的默认实现:

# spring-webmvc-5.3.9.jar!/org/springframework/web/servlet/DispatcherServlet.properties
# Default implementation classes for DispatcherServlet's strategy interfaces.
# Used as fallback when no matching beans are found in the DispatcherServlet context.
# Not meant to be customized by application developers.org.springframework.web.servlet.LocaleResolver=org.springframework.web.servlet.i18n.AcceptHeaderLocaleResolverorg.springframework.web.servlet.ThemeResolver=org.springframework.web.servlet.theme.FixedThemeResolverorg.springframework.web.servlet.HandlerMapping=org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping,\org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping,\org.springframework.web.servlet.function.support.RouterFunctionMappingorg.springframework.web.servlet.HandlerAdapter=org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter,\org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter,\org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter,\org.springframework.web.servlet.function.support.HandlerFunctionAdapterorg.springframework.web.servlet.HandlerExceptionResolver=org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver,\org.springframework.web.servlet.mvc.annotation.ResponseStatusExceptionResolver,\org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolverorg.springframework.web.servlet.RequestToViewNameTranslator=org.springframework.web.servlet.view.DefaultRequestToViewNameTranslatororg.springframework.web.servlet.ViewResolver=org.springframework.web.servlet.view.InternalResourceViewResolverorg.springframework.web.servlet.FlashMapManager=org.springframework.web.servlet.support.SessionFlashMapManager

小结

DispatcherServlet#doDispatch() 是 Spring MVC 处理请求分发的方法,它的处理大体分了 6 步:
1、获取 request 对应的 HandlerExecutionChain(它包含 handler 和 interceptors)
2、获取 handler 对应的 HandlerAdapter
3、执行 handler 的前置处理: HandlerInterceptor#preHandle()
4、通过 HandlerAdapter#handler() 来执行处理程序
5、执行 handler 的后置处理:HandlerInterceptor#postHandle()
6、对返回值进行处理(包括正常返回 和 异常处理)

HandlerExecutionChain 是 handler 的执行链,它是由 handler 和 interceptors 组成的。
HandlerExecutionChain 是由 HandlerMapping#getHandler() 返回的。


http://www.ppmy.cn/news/51113.html

相关文章

【JeecgBoot】Redis 内存到达峰值 100%

文章目录 前言问题排查分析问题设置合理的最大内存限制设置过期时间扩展部分重写配置文件监听键空间事件参考文献前言 今天在访问本地配置的 JeecgBoot 项目发现前端页面一直转圈圈,前端和后端都没有卡死的情况,一般来说如果有死循环或阻塞了,电脑应该呼啦啦的转,开始散热…

后代选择器

知识点&#xff1a; 代码&#xff1a; <!DOCTYPE html> <html lang"en"> <head> <meta charset"UTF-8"> <meta http-equiv"X-UA-Compatible" content"IEedge"> <meta name"viewport" c…

【数据结构:线性表】单链表

在学习了顺序表&#xff0c;我们可能会对其有一些思考&#xff1a; 中间/头部的插入删除&#xff0c;时间复杂度为O(N)增容需要申请新空间&#xff0c;拷贝数据&#xff0c;释放旧空间。会有不小的消耗。增容一般是呈2倍的增长&#xff0c;势必会有一定的空间浪费。例如当前容…

JVM专栏-3.垃圾收集器

在垃圾收集器的上下文中并发和并行的意义 并行&#xff08;Parallel&#xff09;&#xff1a; 并行描述的是多条垃圾收集器线程之间的关系&#xff0c;说明同一时间有多条这样的线程在协同工作&#xff0c;通常默认此时用户线程是处于等待状态的并发&#xff08;Concurrent&…

多线程编程常用函数用法

一、多线程编程常用函数用法 1、pthread_create 头文件 #include<pthread.h>函数声明 int pthread_create(pthread_t*restrict tidp,const pthread_attr_t *restrict_attr,void*&#xff08;*start_rtn)(void*),void *restrict arg)函数功能 pthread_create是UNIX环境…

水果FL Studio21最新中文完整版下载更新及内容介绍

简单总结一下&#xff0c;本次小版本更新最重要的内容&#xff0c;我个人认为是对于M1芯片的适配。其余的比如EQ2&#xff0c;3x这些我们很熟悉的插件虽说也有更新&#xff0c;但是估计并没有特别大的改动。我个人的话会先放一段时间&#xff0c;等下次有其他更让我感兴趣的内容…

oracle 11g等保加固

有个单机环境需要做个等保加固 1、执行如下sql ?/rdbms/admin/utlpwdmg.sql --alter profile default limit password_verify_function null; Alter PROFILE DEFAULT LIMIT PASSWORD_LIFE_TIME 90; alter profile DEFAULT limit password_lock_time 30; alter profile DEFAU…

mysql_exporter在Linux上的安装与配置

mysqld_exporter 是一个用于监控 MySQL 数据库的 Prometheus exporter。可以从 MySQL 数据库的 metrics_schema 收集指标&#xff0c;相关指标主要包括: MySQL 服务器指标:例如 uptime、version 等数据库指标:例如 schema_name、table_rows 等表指标:例如 table_name、engine、…