摘要:接口接口作用是将请求映射到处理程序,以及预处理和处理后的拦截器列表,映射是基于一些标准的,其中的细节因不同的实现而不相同。该参数是类型,作用是检查所有的映射解析器或使用或为的,默认为,即从上下文中检查所有的。
概述
在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 @Nullable HandlerExecutionChain 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,包括父上下文。 MapmatchingBeans = 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"的bean HandlerMapping hm = context.getBean(HANDLER_MAPPING_BEAN_NAME, HandlerMapping.class); // 将hm转换成list,并赋值给属性handlerMappings this.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和RequestMappingHandlerMapping if (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支持,代码如下:
org.springframework spring-webmvc 5.0.5.RELEASE
spring配置文件
spring-servlet.xml是Spring MVC的配置文件,在验证过程中会修改此文件内容,内容根据验证目的会有改变,具体参见验证场景的配置。
web配置文件
web.xml是部署描述文件,主要配置了Spring MVC的DispatcherServlet,代码如下:
dispatcher org.springframework.web.servlet.DispatcherServlet contextConfigLocation classpath:spring-servlet.xml 1 true dispatcher /
Controller控制器
本例使用的是SimpleUrlHandlerMapping映射处理器,所以我们的Controller会继承org.springframework.web.servlet.mvc.Controller类,并实现handlerRequest方法,代码如下:
public class DemoController implements Controller{ @Nullable @Override public 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参数,代码如下:
detectAllHandlerMappings false
在Spring配置文件spring-servlet.xml中定义映射处理器,以SimpleUrlHandlerMapping为例,代码如下:
demoController
打上断点,以debug模式启动服务,结果如下:
从结果可知,Spring取到了我们配置的HandlerMapping(SimpleUrlHandlerMapping)并转换为List赋值给属性参数handlerMappings。
加载所有映射处理器
此场景需要我们配置多个映射处理器,Spring配置文件代码如下:
demoController
注意将web.xml配置的DispatcherServlet的detectAllHandlerMappings注释掉或设置为true
打上断点,以debug模式启动服务,结果如下:
从两种截图中可知,Spring取出了我们配置的所有的映射解析器,对比两种图,可知经过排序,Spring实现了我们指定的解析器的order。
总结本小节分析了HandlerMapping的初始化,过程主要以SimpleUrlHandlerMapping实现类为例,替换成其他的实现类,启动过程也是一样的,后续会对实现类逐个进行分析,希望本章对大家能有帮助。
最后创建了qq群方便大家交流,可扫描加入,共同学习、共同进步,谢谢!
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/69396.html
摘要:概述通过前三章的分析,我们简要分析了和,但对拦截器部分做详细的分析,拦截器的加载和初始化是三个相同的部分。 概述 通过前三章的分析,我们简要分析了SimpleUrlHandlerMapping、BeanNameUrlHandlerMapping和RequestMappingHandlerMapping,但对拦截器部分做详细的分析,拦截器的加载和初始化是三个HandlerMapping相...
摘要:与类图对比,类继承自抽象类,其又继承自抽象类,再往上继承关系与一致。创建初始化上一章我们分析了的创建初始化过程,的创建初始化过程与一样,方法的入口在抽象类中的方法。至此,代码编写完毕。 概述 本节我们继续分析HandlerMapping另一个实现类BeanNameUrlHandlerMapping,从类的名字可知,该类会根据请求的url与spring容器中定义的bean的name属性值...
摘要:概述上一节我们分析了的初始化过程,即创建并注册,本章我们分析下的请求处理过程,即查找。本系列文章是基于。最后创建了群方便大家交流,可扫描加入,同时也可加我,共同学习共同进步,谢谢 概述 上一节我们分析了RequestMappingHandlerMapping的初始化过程,即创建并注册HandlerMehtod,本章我们分析下RequestMappingHandlerMapping的请求...
摘要:由于抽象类重写了父类的方法,所以此时会调用的方法,在该方法中通过调用父类的方法,该方法通过模板方法模式最终调到类的方法。分析该类间接实现了接口,直接实现该接口的是抽象类,映射与请求。 概述 在前一章https://segmentfault.com/a/1190000014901736的基础上继续分析,主要完成SimpleUrlHandlerMapping类的原理。 本系列文章是基于Sp...
摘要:默认支持该策略。以上是对的宏观分析,下面我们进行内部细节分析。整体流程一通过实现接口,完成拦截器相关组件的初始化调用类的方法。总结本文主要分析了的初始化过程,希望对大家有帮助。随着学习的深入,后面有时间在分析下期中涉及的关键,比如等等。 概述 本节我们继续分析HandlerMapping另一个实现类ReqeustMappingHandlerMapping,该类是我们日常开发中使用最多的...
阅读 2892·2021-11-23 09:51
阅读 3142·2021-11-12 10:36
阅读 3169·2021-09-27 13:37
阅读 3139·2021-08-17 10:15
阅读 2571·2019-08-30 15:55
阅读 2714·2019-08-30 13:07
阅读 778·2019-08-29 16:32
阅读 2628·2019-08-26 12:00