SpringMVC在请求到handler处理器的分发这步是通过HandlerMapping模块解决的.handlerMapping 还处理拦截器.

先看看HandlerMapping的继承树吧

可以大致这样做个分类:

  1. 一个接口HandlerMapping,定义一个api: HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception;

  2. 一个基础抽象类:主要是准备上下文环境,提供getHandlerInternal钩子,封装拦截器到HandlerExecutionChain

  3. 基于注解@Controller,@RequestMapping的使用

  4. 配置文件中直接配置url到 handler的SimpleUrlHandlerMapping

  5. 默认实现BeanNameUrlHandlerMapping

  6. Controller子类的映射

看看HandlerMapping吧,就一个getHandler api 非常简单.

// HandlerMapping

  1. package org.springframework.web.servlet;
  2. public interface HandlerMapping {
  3. HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception;
  4.  
  5. }

AbstractHandlerMapping就没有这么简单了

先看AbstractHandlerMapping继承的类,实现的接口

  1. package org.springframework.web.servlet.handler;
  2. public abstract class AbstractHandlerMapping extends WebApplicationObjectSupport
  3. implements HandlerMapping, Ordered {
  4. // ...
  5. }

WebApplicationObjectSupport用于提供上下文ApplicationContext和ServletContext.

  还有这边的initApplicationContext方法,在后续经常会使用到.AbstractHandlerMapping就直接覆写了.

  父类里还是实现了ApplicationContextAware和ServletContextAware接口,spring概念很统一.

Ordered用于集合排序.

再接着看AbstractHandlerMapping的属性吧

// AbstractHandlerMapping

  1. // order赋了最大值,优先级是最小的
  2. private int order = Integer.MAX_VALUE; // default: same as non-Ordered
  3. // 默认的Handler,这边使用的Obejct,子类实现的时候,使用HandlerMethod,HandlerExecutionChain等
  4. private Object defaultHandler;
  5. // url计算的辅助类
  6. private UrlPathHelper urlPathHelper = new UrlPathHelper();
  7. // 基于ant进行path匹配,解决如/books/{id}场景
  8. private PathMatcher pathMatcher = new AntPathMatcher();
  9. // 拦截器配置:1,HandlerMapping属性设置;2,extendInterceptors设置
  10. private final List<Object> interceptors = new ArrayList<Object>();
  11. // 从interceptors中解析得到,直接添加给全部handler
  12. private final List<HandlerInterceptor> adaptedInterceptors = new ArrayList<HandlerInterceptor>();
  13. // 使用前需要跟url进行匹配,匹配通过才会使用
  14. private final List<MappedInterceptor> mappedInterceptors = new ArrayList<MappedInterceptor>();

看下拦截器的初始化:

// AbstractHandlerMapping

  1. @Override
  2. protected void initApplicationContext() throws BeansException {
  3. extendInterceptors(this.interceptors);
  4. detectMappedInterceptors(this.mappedInterceptors);
  5. initInterceptors();
  6. }
  7.  
  8. /**
  9. * 提供给子类扩展拦截器,可惜都没有使用
  10. */
  11. protected void extendInterceptors(List<Object> interceptors) {
  12. }
  13.  
  14. /**
  15. * 扫描应用下的MappedInterceptor,并添加到mappedInterceptors
  16. */
  17. protected void detectMappedInterceptors(List<MappedInterceptor> mappedInterceptors) {
  18. mappedInterceptors.addAll(
  19. BeanFactoryUtils.beansOfTypeIncludingAncestors(
  20. getApplicationContext(),MappedInterceptor.class, true, false).values());
  21. }
  22.  
  23. /**
  24. * 归集MappedInterceptor,并适配HandlerInterceptor和WebRequestInterceptor
  25. */
  26. protected void initInterceptors() {
  27. if (!this.interceptors.isEmpty()) {
  28. for (int i = 0; i < this.interceptors.size(); i++) {
  29. Object interceptor = this.interceptors.get(i);
  30. if (interceptor == null) {
  31. throw new IllegalArgumentException("Entry number " + i + " in interceptors array is null");
  32. }
  33. if (interceptor instanceof MappedInterceptor) {
  34. mappedInterceptors.add((MappedInterceptor) interceptor);
  35. }
  36. else {
  37. adaptedInterceptors.add(adaptInterceptor(interceptor));
  38. }
  39. }
  40. }
  41. }
  42.  
  43. protected HandlerInterceptor adaptInterceptor(Object interceptor) {
  44. if (interceptor instanceof HandlerInterceptor) {
  45. return (HandlerInterceptor) interceptor;
  46. }
  47. else if (interceptor instanceof WebRequestInterceptor) {
  48. return new WebRequestHandlerInterceptorAdapter((WebRequestInterceptor) interceptor);
  49. }
  50. else {
  51. throw new IllegalArgumentException("Interceptor type not supported: " + interceptor.getClass().getName());
  52. }
  53. }

然后是getHandler(HttpServletRequest request)的实现,这边同时预留getHandlerInternal(HttpServletRequest request)给子类实现

// AbstractHandlerMapping

  1. public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
  2. Object handler = getHandlerInternal(request);
  3. if (handler == null) {
  4. handler = getDefaultHandler();
  5. }
  6. if (handler == null) {
  7. return null;
  8. }
  9. // Bean name or resolved handler?
  10. if (handler instanceof String) {
  11. String handlerName = (String) handler;
  12. handler = getApplicationContext().getBean(handlerName);
  13. }
  14. return getHandlerExecutionChain(handler, request);
  15. }
  16.  
  17. protected abstract Object getHandlerInternal(HttpServletRequest request) throws Exception;

最后是封装拦截器到HandlerExecutionChain

  adaptedInterceptors直接添加

  mappedInterceptors需要根据url匹配通过后添加

// AbstractHandlerMapping

  1. protected HandlerExecutionChain getHandlerExecutionChain(Object handler, HttpServletRequest request) {
  2. HandlerExecutionChain chain =
  3. (handler instanceof HandlerExecutionChain) ?
  4. (HandlerExecutionChain) handler : new HandlerExecutionChain(handler);
  5.  
  6. chain.addInterceptors(getAdaptedInterceptors());
  7.  
  8. String lookupPath = urlPathHelper.getLookupPathForRequest(request);
  9. for (MappedInterceptor mappedInterceptor : mappedInterceptors) {
  10. if (mappedInterceptor.matches(lookupPath, pathMatcher)) {
  11. chain.addInterceptor(mappedInterceptor.getInterceptor());
  12. }
  13. }
  14.  
  15. return chain;
  16. }

Controller子类的映射,这一分支先看类继承

我们来说说,这边每个类主要的职责

  1. AbstractHandlerMapping 准备上下文环境;提供getHandlerInternal钩子;封装拦截器到HandlerExecutionChain

  2. AbstractUrlHandlerMapping 实现注册handler的方法供子类使用;实现getHandlerInternal,根据子类初始化的配置信息,查找handler

  3. AbstractDetectingUrlHandlerMapping 扫描应用下的Object,迭代后提供钩子方法determineUrlsForHandler由子类决定如何过滤

  4. AbstractControllerUrlHandlerMapping 实现determineUrlsForHandler,添加过滤排除的handler操作(配置文件配置),预留钩子方法buildUrlsForHandler给子类实现;同时判断controller的子类

  5. ControllerBeanNameHandlerMapping 根据bean name生成url

    ControllerClassNameHandlerMapping根据class name生成url

从AbstractUrlHandlerMapping开始看吧,这边只是大致看下代码,如果需要仔细分析,请移步<SpringMVC源码解读 - HandlerMapping - AbstractUrlHandlerMapping系列request分发>

handler的注册

  1. protected void registerHandler(String[] urlPaths, String beanName) throws BeansException, IllegalStateException { }
  2.  
  3. protected void registerHandler(String urlPath, Object handler) throws BeansException, IllegalStateException { }

handler的查找

  1. protected Object getHandlerInternal(HttpServletRequest request) throws Exception {}
  2. // 根据url查找handler
  3. protected Object lookupHandler(String urlPath, HttpServletRequest request) throws Exception {}
  4. // 校验handler
  5. protected void validateHandler(Object handler, HttpServletRequest request) throws Exception {}
  6. // 封装拦截器到HandlerExecutionChain
  7. protected Object buildPathExposingHandler(Object rawHandler, String bestMatchingPattern,
  8. String pathWithinMapping, Map<String, String> uriTemplateVariables) {}

AbstractDetectingUrlHandlerMapping,这边一样不展开,具体移步<SpringMVC源码解读 - HandlerMapping - AbstractDetectingUrlHandlerMapping系列初始化>

具体做的事情:

  1. 通过覆写initApplicationContext,调用detectHandlers扫描Obejct

  2. 提供钩子方法determineUrlsForHandler给子类根据handler生成url

  3. 调用父类的registerHandler进行注册

  1. @Override
  2. public void initApplicationContext() throws ApplicationContextException {
  3. super.initApplicationContext();
  4. detectHandlers();
  5. }
  6.  
  7. protected void detectHandlers() throws BeansException {
  8. // ...
  9. }
  10.  
  11. /**
  12. * Determine the URLs for the given handler bean.
  13. * 钩子而已
  14. */
  15. protected abstract String[] determineUrlsForHandler(String beanName);

AbstractControllerUrlHandlerMapping,这边一样不展开,具体移步<SpringMVC源码解读 - HandlerMapping - AbstractDetectingUrlHandlerMapping系列初始化>

具体做的事情;

  1. 覆写determineUrlsForHandler添加剔除部分类的逻辑,通过配置文件配置的excludedClasses和excludedPackages在这边使用

  2. 判断是否controller的子类

  3. 预留buildUrlsForHandler给子类生成url

  1. @Override
  2. protected String[] determineUrlsForHandler(String beanName) {
  3. Class beanClass = getApplicationContext().getType(beanName);
  4. if (isEligibleForMapping(beanName, beanClass)) {
  5. return buildUrlsForHandler(beanName, beanClass);
  6. }
  7. else {
  8. return null;
  9. }
  10. }
  11.  
  12. protected boolean isEligibleForMapping(String beanName, Class beanClass) {}
  13.  
  14. protected boolean isControllerType(Class beanClass) {}
  15.  
  16. protected abstract String[] buildUrlsForHandler(String beanName, Class beanClass);

ControllerBeanNameHandlerMapping和ControllerClassNameHandlerMapping 直接看源码吧,或者移步<SpringMVC源码解读 - HandlerMapping - AbstractDetectingUrlHandlerMapping系列初始化>

配置文件中直接配置url到 handler的SimpleUrlHandlerMapping,就是使用registerHandlers注册配置文档中的handler,直接看代码或者移步<SpringMVC源码解读 - HandlerMapping - SimpleUrlHandlerMapping初始化>吧

BeanNameUrlHandlerMapping 实现determineUrlsForHandler生成url,直接看代码或者移步<SpringMVC源码解读 - HandlerMapping - AbstractDetectingUrlHandlerMapping系列初始化>吧

基于注解@Controller,@RequestMapping的使用

最难吭的骨头

先看类继承吧

说下各个类的职责吧,具体的分析还是移步下面的文章

<SpringMVC源码解读 - HandlerMapping - RequestMappingHandlerMapping初始化>

<SpringMVC源码解读 - HandlerMapping - RequestMappingHandlerMapping请求分发>

  1. AbstractHandlerMethodMaping 定义初始化流程,请求时如何映射

  初始化:

    1.1.1 扫描应用下的Object

    1.1.2 预留isHandler钩子方法给子类判断Object是否handler

    1.1.3 迭代扫描每一个handler,找出符合要求的方法,这边判断依然是留给子类实现getMappingForMethod

    1.1.4 注册查找到的处理器,需要确保一个匹配条件RequestMappingInfo只能映射到一个handler

    1.1.5 根据匹配条件获取url,同样的只是定义流程,具体的算法留给子类实现getMappingPathPatterns

  请求request分发处理:

    1.2.1 直接字符串匹配的方式,查找handler 

    1.2.2 匹配条件查找,这边具体的算法交由子类处理getMatchingMapping

    1.2.3 排序并获取最佳匹配handler,这边的排序方式还是子类处理getMappingConmparator

    1.2.4 分别封装匹配到和未匹配到handler的情况

  2. RequestMappingInfoHandlerMapping使用RequestMappingInfo实现匹配条件,RequestMappingInfo的初始化留给子类

    2.1 根据RequestMappingInfo生成url   ->getMappingPathPatterns

    2.2 使用匹配条件查找Handler -> getMatchingMapping

    2.3 完成比较器算法 -> getMappingComparator

    2.4 覆写handleMatch,缓存n多信息到request

      注册pattern,最佳匹配的pattern,url中解析出来的参数,url中解析出来的多值参数,mediaType

    2.1.5 覆写handlerNoMatch,最后的挣扎,再尝试匹配一次

  3. RequestMappingHandlerMapping 根据注解@Controller @RequestMapping生成RequestMappingInfo,并校验isHandler

    3.1 覆写afterPropertiesSet,添加文件后缀判断

    3.2 实现isHandler,类上有@Controller @RequestMapping其中一个注解就对

    3.3 解析注解内容,生产RequestMappingInfo实例

      

  

SpringMVC源码解读 - HandlerMapping的更多相关文章

  1. SpringMVC源码解读 - HandlerMapping - RequestMappingHandlerMapping请求分发

    AbstractHandlerMethodMapping实现接口getHandlerInternal,定义查找流程 RequestMappingInfoHandlerMapping根据RequestM ...

  2. SpringMVC源码解读 - HandlerMapping - AbstractUrlHandlerMapping系列request分发

    AbstractHandlerMapping实现HandlerMapping接口定的getHandler 1. 提供getHandlerInternal模板方法给子类实现 2. 如果没有获取Handl ...

  3. SpringMVC源码解读 - HandlerMapping - SimpleUrlHandlerMapping初始化

    摘要: SimpleUrlHandlerMapping只是参与Handler的注册,请求映射时由AbstractUrlHandlerMapping搞定. 初始化时,通过setMappings(Prop ...

  4. SpringMVC源码解读 - HandlerMapping - RequestMappingHandlerMapping初始化

    RequestMappingHandlerMapping ,用于注解@Controller,@RequestMapping来定义controller. @Controller @RequestMapp ...

  5. SpringMVC源码解读 - HandlerMapping - AbstractDetectingUrlHandlerMapping系列初始化

    AbstractDetectingUrlHandlerMapping是通过扫描方式注册Handler,收到请求时由AbstractUrlHandlerMapping的getHandlerInterna ...

  6. SpringMVC源码解读 - RequestMapping注解实现解读 - RequestCondition体系

    一般我们开发时,使用最多的还是@RequestMapping注解方式. @RequestMapping(value = "/", param = "role=guest& ...

  7. SpringMVC源码解读 - RequestMapping注解实现解读

    SpringMVC源码解读 - RequestMapping注解实现解读 - RequestCondition体系  https://www.cnblogs.com/leftthen/p/520840 ...

  8. SpringMVC源码解读 - RequestMapping注解实现解读 - RequestMappingInfo

    使用@RequestMapping注解时,配置的信息最后都设置到了RequestMappingInfo中. RequestMappingInfo封装了PatternsRequestCondition, ...

  9. springMVC源码分析--HandlerMapping(一)

    HandlerMapping的工作就是为每个请求找到合适的请求找到一个处理器handler,其实现机制简单来说就是维持了一个url到Controller关系的Map结构,其提供的实际功能也是根据req ...

随机推荐

  1. 黄聪:VPS配置Filezilla Server支持FTP的Passive被动模式(FTP连接不上怎么办?有详细教程)

    Filezilla Server的配置: 1.Filezilla默认的模式是Port模式,不是Passive被动模式.为了解决防火墙后的客户端连接问题,最好是启用Passive模式.要启动被动模式,首 ...

  2. 内核程序开发 LED灯顺序点亮、顺序熄灭

    根据实际考试情况,你要按顺序这么来干. 首先,把老师给的文件1.LED灯顺序点亮.顺序熄灭导入到虚拟机里你喜欢的目录下 进入此目录1.LED灯顺序点亮.顺序熄灭: 看到这三个文件,依次打开背过,老师出 ...

  3. UE4 的json读写方式

    转自:http://blog.csdn.net/cartzhang/article/details/41009343 JSON 的解析有很多开源库.UE4的JSON使用在代码的Public->S ...

  4. Spring中使用JDBC

    Spring中的数据库异常体系 使用JDBC(不使用Spring)的时候,我们需要强制捕获SQLException,否则无法使用JDBC处理任何事情.SQLException表示尝试访问数据库的时候出 ...

  5. 精《Linux内核精髓:精通Linux内核必会的75个绝技》一HACK #8 调度策略

    HACK #8 调度策略 本节介绍Linux的调度策略(scheduling policy).Linux调度策略的类别大致可以分为TSS(Time Sharing System,分时系统)和实时系统这 ...

  6. Ubuntu 中安装 Docker

    检查 Device Mapper 是否存在 sch01ar@ubuntu:~$ ls -l /sys/class/misc/device-mapper 安装 Ubuntu 维护的版本 sch01ar@ ...

  7. springboot 邮件服务

    springboot仍然在狂速发展,才五个多月没有关注,现在看官网已经到1.5.3.RELEASE版本了.准备慢慢在写写springboot相关的文章,本篇文章使用springboot最新版本1.5. ...

  8. 集合-强大的集合工具类:java.util.Collections中未包含的集合工具

    任何对JDK集合框架有经验的程序员都熟悉和喜欢java.util.Collections包含的工具方法.Guava沿着这些路线提供了更多的工具方法:适用于所有集合的静态方法.这是Guava最流行和成熟 ...

  9. Direcshow之视频捕捉<转>

    关于视频捕捉(About Video Capture in Dshow) 1. 视频捕捉Graph的构建 一个能够捕捉音频或者视频的graph图都称之为捕捉graph图.捕捉graph图比一般的文件回 ...

  10. mysql性能优化-慢查询分析、优化索引和配置【转】

    一.优化概述 二.查询与索引优化分析 1性能瓶颈定位 Show命令 慢查询日志 explain分析查询 profiling分析查询 2索引及查询优化 三.配置优化 1)      max_connec ...