SpringMVC之源码分析--HandlerMapping(一)
概述
在Spring MVC启动章节https://segmentfault.com/a/1190000014674239,介绍到了DispatcherServlet的onRefresh方法调用initStrategies方法,初始Spring MVC九大策略解析器,本章在此基础上分析初始化HandlerMapping组件过程,本系列文章是基于Spring5.0.5RELEASE。
接口
HandlerMapping接口作用是将请求映射到处理程序,以及预处理和处理后的拦截器列表,映射是基于一些标准的,其中的细节因不同的实现而不相同。这是官方文档上一段描述,该接口只有一个方法getHandler(request),返回一个HandlerExecutionChain对象,接口本身很简单,源码如下:
public interface HandlerMapping {省略属性...// 返回请求的一个处理程序handler和拦截器interceptors@NullableHandlerExecutionChain getHandler(HttpServletRequest request) throws Exception;
}
初始化
初始化HandlerMapping的入口方法是DispatcherServlet的initHandlerMappings(ApplicationContext context)方法,该方法源码如下:
private void initHandlerMappings(ApplicationContext context) {this.handlerMappings = null;// detectAllHandlerMappings默认为true,可通过DispatcherServlet的init-param参数进行设置if (this.detectAllHandlerMappings) {// 在ApplicationContext中找到所有的handlerMapping,包括父上下文。Map<String, HandlerMapping> matchingBeans =BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerMapping.class, true, false);if (!matchingBeans.isEmpty()) {this.handlerMappings = new ArrayList<>(matchingBeans.values());// 对handlerMapping排序,可通过指定order属性进行设置,order的值为int型,数越小优先级越高AnnotationAwareOrderComparator.sort(this.handlerMappings);}}// detectAllHandlerMappings=false时else { try {// 从ApplicationContext上下文中取id(或name)="handlerMapping"的beanHandlerMapping hm = context.getBean(HANDLER_MAPPING_BEAN_NAME, HandlerMapping.class);// 将hm转换成list,并赋值给属性handlerMappingsthis.handlerMappings = Collections.singletonList(hm);}catch (NoSuchBeanDefinitionException ex) {// Ignore, we'll add a default HandlerMapping later.}}// 从context上下文中定义HandlerMapping时,Spring MVC将使用默认HandlerMapping,默认的HandlerMapping在DispatcherServlet.properties属性文件中定义,// 该文件是在DispatcherServlet的static静态代码块中加载的// 默认的是:BeanNameUrlHandlerMapping和RequestMappingHandlerMappingif (this.handlerMappings == null) {this.handlerMappings = getDefaultStrategies(context, HandlerMapping.class);if (logger.isDebugEnabled()) {logger.debug("No HandlerMappings found in servlet '" + getServletName() + "': using default");}}
}
至此,我们基本分析了HandlerMapping的初始化过程,接下来针对分析中提到的点进行验证,以检验我们的分析是正确的。
实战
- 项目结构
代码分析
pom配置文件
引入Spring MVC支持,代码如下:
<dependency><groupId>org.springframework</groupId><artifactId>spring-webmvc</artifactId><version>5.0.5.RELEASE</version> </dependency>
- spring配置文件
spring-servlet.xml是Spring MVC的配置文件,在验证过程中会修改此文件内容,内容根据验证目的会有改变,具体参见验证场景的配置。
web配置文件
web.xml是部署描述文件,主要配置了Spring MVC的DispatcherServlet,代码如下:
<servlet><!-- Servlet名称,可任意定义,但必须与servlet-mapping中对应 --><servlet-name>dispatcher</servlet-name><!-- 指定Spring MVC核心控制类,即J2EE规范中的前端控制器(Front Controller) --><servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class><!-- 指定Spring MVC配置文件,默认在WEB-INF目录下,切名字为[servlet-name]-servlet.xml,此文件中配置web相关内容,比如:指定扫描Controller路径、配置逻辑视图前缀后缀、上传文件等等 --><init-param><param-name>contextConfigLocation</param-name><param-value>classpath:spring-servlet.xml</param-value></init-param><!-- 此配置的值为正整数时,表示容器启动时初始化,即调用Servlet的init方法 --><load-on-startup>1</load-on-startup><async-supported>true</async-supported> </servlet> <!-- 定义servlet映射 --> <servlet-mapping><!-- 与servlet中servlet-name对应 --><servlet-name>dispatcher</servlet-name><!-- 映射所有的url --><url-pattern>/</url-pattern> </servlet-mapping>
Controller控制器
本例使用的是SimpleUrlHandlerMapping映射处理器,所以我们的Controller会继承
org.springframework.web.servlet.mvc.Controller
类,并实现handlerRequest方法,代码如下:public class DemoController implements Controller{@Nullable@Overridepublic ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception {request.getServletContext().log("进入Controller(Handler)处理器。。。");return null;} }
验证
- 默认映射处理器
在我们没有对HandlerMapping进行配置时,Spring会使用默认的HandlerMapping策略,此时我们的Spring配置文件(spring-servlet.xml)没有任何内容,此时我们启动应用,通过断点方式验证,结果如下:
Spring MVC默认配置为:
从结果可知,在未进行任何配置HandlerMapping时,系统使用(支持)默认的BeanNameUrlHandlerMapping和RequestMappingHandlerMapping映射解析器。
detectAllHandlerMappings
该参数是boolean类型,作用是检查所有的HandlerMappings映射解析器或使用id或name为"handlerMappping"的bean,默认为true,即从context上下文中检查所有的HandlerMapping。
我们先通过修改此参数为false,即在web.xml配置DispatcherServlet时,设置init-param参数,代码如下:
<!-- 使用id或name为handlerMapping的映射处理器 --> <init-param><param-name>detectAllHandlerMappings</param-name><param-value>false</param-value> </init-param>
在Spring配置文件spring-servlet.xml中定义映射处理器,以SimpleUrlHandlerMapping为例,代码如下:
<!-- 定义映射处理器 --> <bean id="handlerMapping" class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping"><property name="urlMap"><props><prop key="/demo">demoController</prop></props></property><!-- 设置顺序,在多个映射处理器时用于排序,可不设置 --><property name="order" value="1"/> </bean><bean id="demoController" class="com.github.dalianghe.controller.DemoController"/>
打上断点,以debug模式启动服务,结果如下:
从结果可知,Spring取到了我们配置的HandlerMapping(SimpleUrlHandlerMapping)并转换为List赋值给属性参数handlerMappings。
加载所有映射处理器
此场景需要我们配置多个映射处理器,Spring配置文件代码如下:
<bean id="handlerMapping" class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping"><property name="urlMap"><props><prop key="/demo">demoController</prop></props></property><property name="order" value="1"/> </bean><bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"><property name="order" value="0"/> </bean>
注意将web.xml配置的DispatcherServlet的detectAllHandlerMappings注释掉或设置为true
打上断点,以debug模式启动服务,结果如下:
从两种截图中可知,Spring取出了我们配置的所有的映射解析器,对比两种图,可知经过排序,Spring实现了我们指定的解析器的order。
- 默认映射处理器
总结
本小节分析了HandlerMapping的初始化,过程主要以SimpleUrlHandlerMapping实现类为例,替换成其他的实现类,启动过程也是一样的,后续会对实现类逐个进行分析,希望本章对大家能有帮助。
最后创建了qq群方便大家交流,可扫描加入,共同学习、共同进步,谢谢!
SpringMVC之源码分析--HandlerMapping(一)相关推荐
- SpringMVC之源码分析--ViewResolver(四)
概述 本章继续学习ViewResolver另一个实现类ContentNegotiatingViewResolver解析器,该类的主要作用是根据同一请求的某些策略,选择对应的View进行渲染.可以把Co ...
- SpringMVC之源码分析--LocaleResolver和ThemeResolver应用
概述 以上分析了Spring MVC的LocaleResolver和ThemeResolver两个策略解析器,在实际项目中很少使用,尤其是ThemeResolver,花精力去分析他们,主要是为了系统的 ...
- SpringMVC之源码分析--ThemeResolver(三)
概述 上节介绍了SessionThemeResolver解析器,本章分析下CookieThemeResolver,两个解析器实现的功能是一样的,只是使用的主题载体有区别而已,SessionThemeR ...
- SpringMVC源码分析系列[转]
说到java的mvc框架,struts2和springmvc想必大家都知道,struts2的设计基本上完全脱离了Servlet容器,而springmvc是依托着Servlet容器元素来设计的,同时sp ...
- SpringMVC源码分析系列
说到java的mvc框架,struts2和springmvc想必大家都知道,struts2的设计基本上完全脱离了Servlet容器,而springmvc是依托着Servlet容器元素来设计的,同时sp ...
- SpringMVC源码分析(4)剖析DispatcherServlet重要组件
简单介绍了一个请求的处理过程, 简略描述了调用过程,并没有涉及过多细节,如url匹配,报文解析转换等. <SpringMVC源码分析(2)DispatcherServlet的初始化>:介绍 ...
- 详解SpringMVC中Controller的方法中参数的工作原理[附带源码分析]
目录 前言 现象 源码分析 HandlerMethodArgumentResolver与HandlerMethodReturnValueHandler接口介绍 HandlerMethodArgumen ...
- modelandview使用过程_深入源码分析SpringMVC执行过程
本文主要讲解 SpringMVC 执行过程,并针对相关源码进行解析. 首先,让我们从 Spring MVC 的四大组件:前端控制器(DispatcherServlet).处理器映射器(HandlerM ...
- 详解SpringMVC中Controller的方法中参数的工作原理[附带源码分析] good
目录 前言 现象 源码分析 HandlerMethodArgumentResolver与HandlerMethodReturnValueHandler接口介绍 HandlerMethodArgumen ...
最新文章
- CICC科普栏目|颠覆认知!看完这些图,你的世界观还好吗?
- 退出python命令行-在cmd命令行里进入和退出Python程序的方法
- mysql数据库的字符串表示什么意思_MySQL数据库的字符串类型详解(01)
- python的des和3des加解密
- 网页登陆验证之图片验证码
- [python 练习] 计算个税
- lambda ::表达式_Lambda表达式和流API:基本示例
- 微信支付崩溃,却开启区块链数字货币大门?
- 制造-销售”模式正在消亡,传统大型企业的上云之路要如何举步?
- java 判断double是否为整数_java 中如何判断输入的是int还是double
- [RK3399][Android7.1] ADB功能怎么Debug
- 怎样用UE4把一个Actor直接打包成Pak
- vba九九乘法表代码_VBA程序控制结构示例-九九乘法表
- Qt5 与OpenCV4教程一:Qt5.12安装与OpenCV4.5.0配置
- Centos Siege测试使用
- word转html制作操作手册,Word文档转换为HTML帮助文档操作手册范本.pdf
- mysql 表分区修复,硬盘分区表损坏后的数据恢复方法
- c语言分数乘法,武汉小学数学六年级
- 火线、地线、零线区别
- 使用ADF Faces 之二:数据可视化组件 Thematic Map