概述

在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(一)相关推荐

  1. SpringMVC之源码分析--ViewResolver(四)

    概述 本章继续学习ViewResolver另一个实现类ContentNegotiatingViewResolver解析器,该类的主要作用是根据同一请求的某些策略,选择对应的View进行渲染.可以把Co ...

  2. SpringMVC之源码分析--LocaleResolver和ThemeResolver应用

    概述 以上分析了Spring MVC的LocaleResolver和ThemeResolver两个策略解析器,在实际项目中很少使用,尤其是ThemeResolver,花精力去分析他们,主要是为了系统的 ...

  3. SpringMVC之源码分析--ThemeResolver(三)

    概述 上节介绍了SessionThemeResolver解析器,本章分析下CookieThemeResolver,两个解析器实现的功能是一样的,只是使用的主题载体有区别而已,SessionThemeR ...

  4. SpringMVC源码分析系列[转]

    说到java的mvc框架,struts2和springmvc想必大家都知道,struts2的设计基本上完全脱离了Servlet容器,而springmvc是依托着Servlet容器元素来设计的,同时sp ...

  5. SpringMVC源码分析系列

    说到java的mvc框架,struts2和springmvc想必大家都知道,struts2的设计基本上完全脱离了Servlet容器,而springmvc是依托着Servlet容器元素来设计的,同时sp ...

  6. SpringMVC源码分析(4)剖析DispatcherServlet重要组件

    简单介绍了一个请求的处理过程, 简略描述了调用过程,并没有涉及过多细节,如url匹配,报文解析转换等. <SpringMVC源码分析(2)DispatcherServlet的初始化>:介绍 ...

  7. 详解SpringMVC中Controller的方法中参数的工作原理[附带源码分析]

    目录 前言 现象 源码分析 HandlerMethodArgumentResolver与HandlerMethodReturnValueHandler接口介绍 HandlerMethodArgumen ...

  8. modelandview使用过程_深入源码分析SpringMVC执行过程

    本文主要讲解 SpringMVC 执行过程,并针对相关源码进行解析. 首先,让我们从 Spring MVC 的四大组件:前端控制器(DispatcherServlet).处理器映射器(HandlerM ...

  9. 详解SpringMVC中Controller的方法中参数的工作原理[附带源码分析] good

    目录 前言 现象 源码分析 HandlerMethodArgumentResolver与HandlerMethodReturnValueHandler接口介绍 HandlerMethodArgumen ...

最新文章

  1. CICC科普栏目|颠覆认知!看完这些图,你的世界观还好吗?
  2. 退出python命令行-在cmd命令行里进入和退出Python程序的方法
  3. mysql数据库的字符串表示什么意思_MySQL数据库的字符串类型详解(01)
  4. python的des和3des加解密
  5. 网页登陆验证之图片验证码
  6. [python 练习] 计算个税
  7. lambda ::表达式_Lambda表达式和流API:基本示例
  8. 微信支付崩溃,却开启区块链数字货币大门?
  9. 制造-销售”模式正在消亡,传统大型企业的上云之路要如何举步?
  10. java 判断double是否为整数_java 中如何判断输入的是int还是double
  11. [RK3399][Android7.1] ADB功能怎么Debug
  12. 怎样用UE4把一个Actor直接打包成Pak
  13. vba九九乘法表代码_VBA程序控制结构示例-九九乘法表
  14. Qt5 与OpenCV4教程一:Qt5.12安装与OpenCV4.5.0配置
  15. Centos Siege测试使用
  16. word转html制作操作手册,Word文档转换为HTML帮助文档操作手册范本.pdf
  17. mysql 表分区修复,硬盘分区表损坏后的数据恢复方法
  18. c语言分数乘法,武汉小学数学六年级
  19. 火线、地线、零线区别
  20. 使用ADF Faces 之二:数据可视化组件 Thematic Map

热门文章

  1. windows的bpython安装方法以及数据库报错--记录
  2. CSharpGL(36)通用的非托管数组排序方法
  3. [Lua学习]简单链表
  4. 读书笔记2013-1--暗时间(刘未鹏)
  5. symantec 5220牛刀小试系列(二)
  6. 剑道训练很有趣的一种手段
  7. docker mysql开机自启动_Docker学习4-学会如何让容器开机自启服务【坑】
  8. MySQL高级 - 锁 - MyISAM表锁 - 读锁
  9. 初识Docker-Docker架构
  10. Spring用户自定义类型