请求具体过程

一、HandlerMapping

Interface to be implemented by objects that define a mapping between requests and handler objects.

    HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception;

HandlerExecutionChain(包含一个处理器 handler 如HandlerMethod 对象、多个 HandlerInterceptor 拦截器对象)

  • RequestMappingHandlerMapping 的映射关系由 MappingRegistry 维护,通过多个map联结,即可找到请求对应的处理器
  • RequestMappingHandlerMapping 的映射关系初始化入口是 afterProperties 方法,因为其实现了接口 InitializingBean

SpringMVC的请求处理过程中的路径匹配过程(AbstractHandlerMethodMapping#lookupHandlerMethod)

    protected HandlerMethod lookupHandlerMethod(String lookupPath, HttpServletRequest request) throws Exception {
List<Match> matches = new ArrayList<Match>();
List<T> directPathMatches = this.mappingRegistry.getMappingsByUrl(lookupPath);
if (directPathMatches != null) {
addMatchingMappings(directPathMatches, matches, request);
}
if (matches.isEmpty()) {
// 如正则匹配、RESTFUL路径/list/{cityId}等,这里可以改进,No choice but to go through all mappings...
addMatchingMappings(this.mappingRegistry.getMappings().keySet(), matches, request);
} if (!matches.isEmpty()) {
Comparator<Match> comparator = new MatchComparator(getMappingComparator(request));
Collections.sort(matches, comparator);
if (logger.isTraceEnabled()) {
logger.trace("Found " + matches.size() + " matching mapping(s) for [" +
lookupPath + "] : " + matches);
}
Match bestMatch = matches.get(0);
if (matches.size() > 1) {
if (CorsUtils.isPreFlightRequest(request)) {
return PREFLIGHT_AMBIGUOUS_MATCH;
}
Match secondBestMatch = matches.get(1);
if (comparator.compare(bestMatch, secondBestMatch) == 0) {
Method m1 = bestMatch.handlerMethod.getMethod();
Method m2 = secondBestMatch.handlerMethod.getMethod();
throw new IllegalStateException("Ambiguous handler methods mapped for HTTP path '" +
request.getRequestURL() + "': {" + m1 + ", " + m2 + "}");
}
}
handleMatch(bestMatch.mapping, lookupPath, request);
return bestMatch.handlerMethod;
}
else {
return handleNoMatch(this.mappingRegistry.getMappings().keySet(), lookupPath, request);
}
}

RequestMappingHandlerMapping根据,细化匹配条件,整体的查找过程如下:

1.1 从urlMap中直接等值匹配查找匹配条件RequestMappingInfo

1.2 如果等值查找到匹配条件,将其添加到match条件中

1.3 如果没有找到匹配条件,使用所有的handlerMethod的RequestMappingInfo进行匹配

1.4 对匹配到的Match进行排序,取出最高优先级的Match,并核对是否是唯一的最高优先级

二、获取HandlerExecutionChain(AbstractHandlerMapping#getHandler)

    @Override
public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
     //模板方法
Object handler = getHandlerInternal(request);
if (handler == null) {
handler = getDefaultHandler();
}
if (handler == null) {
return null;
}
// Bean name or resolved handler?
if (handler instanceof String) {
String handlerName = (String) handler;
handler = getApplicationContext().getBean(handlerName);
}
     //把Handler和HandlerInterceptor包裹成HandlerExecutionChain
HandlerExecutionChain executionChain = getHandlerExecutionChain(handler, request);
if (CorsUtils.isCorsRequest(request)) {
CorsConfiguration globalConfig = this.corsConfigSource.getCorsConfiguration(request);
CorsConfiguration handlerConfig = getCorsConfiguration(handler, request);
CorsConfiguration config = (globalConfig != null ? globalConfig.combine(handlerConfig) : handlerConfig);
executionChain = getCorsHandlerExecutionChain(request, executionChain, config);
}
return executionChain;
}

3.getHandlerExecutionChain调用

    protected HandlerExecutionChain getHandlerExecutionChain(Object handler, HttpServletRequest request) {
     //为啥这里要做判断,因为DispatchServlet里面的doDispatch调用getHandler返回的是HandlerExecutionChain
HandlerExecutionChain chain = (handler instanceof HandlerExecutionChain ?
(HandlerExecutionChain) handler : new HandlerExecutionChain(handler)); String lookupPath = this.urlPathHelper.getLookupPathForRequest(request);
for (HandlerInterceptor interceptor : this.adaptedInterceptors) {
if (interceptor instanceof MappedInterceptor) {
MappedInterceptor mappedInterceptor = (MappedInterceptor) interceptor;
if (mappedInterceptor.matches(lookupPath, this.pathMatcher)) {
chain.addInterceptor(mappedInterceptor.getInterceptor());
}
}
else {
chain.addInterceptor(interceptor);
}
}
return chain;
}

三、选择使用HandlerMapping

如何选择合适的HandlerMapping

    protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
for (HandlerMapping hm : this.handlerMappings) {
if (logger.isTraceEnabled()) {
logger.trace(
"Testing handler map [" + hm + "] in DispatcherServlet with name '" + getServletName() + "'");
}
       //如何选择不同的HandlerMapping
HandlerExecutionChain handler = hm.getHandler(request);
if (handler != null) {
return handler;
}
}
return null;
}

springMVC(五): 通过 HandlerMapping 获取 HandlerExecutionChain的更多相关文章

  1. java:JavaScript2:(setTimeout定时器,history.go()前进/后退,navigator.userAgent判断浏览器,location.href,五种方法获取标签属性,setAttribute,innerHTML,三种方法获取form表单信息,JS表单验证,DOM对象,form表单操作)

    1.open,setTimeout,setInterval,clearInterval,clearTimeout <!DOCTYPE> <html> <head> ...

  2. SpringMVC请求参数的获取方式

    一.GET请求参数获取 1. 通过HttpServletRequest获取参数 2. 直接方法参数获取 3. RequestParam注解方式获取请求参数 4. Bean方式获取参数 5. Model ...

  3. SpringMVC工作原理 : HandlerMapping和HandlerAdapter

    一.HandlerMapping 作用是根据当前请求的找到对应的 Handler,并将 Handler(执行程序)与一堆 HandlerInterceptor(拦截器)封装到 HandlerExecu ...

  4. SpringMVC(关于HandlerMapping执行流程原理分析)

    请求过来先碰见中央调度器(前端调度器) //Determine handler for the current request; 对当前请求决定交给哪个handler, 当前请求地址过来 处理器执行链 ...

  5. springmvc(五) 数据回显与自定义异常处理器

    这章讲解一下springmvc的数据回显和自定义异常处理器的使用,两个都很简单 --WH 一.数据回显技术 Springmvc默认支持对pojo类型的数据回显,默认不支持简单类型的数据回显 1.1.什 ...

  6. SpringMVC请求使用@PathVariable获取文件名称并且文件名中存在.导致路径被截取的问题

    在SpringMVC中,当使用@pathVariable通过Get请求获取路径名称时,如果路径名称上存在小数点,则获取不到小数点后面的内容,会被Spring截取. 比如我获取某一文件,路径是local ...

  7. SpringMVC传递参数和获取参数以及返回数据

    1.传递form表单,参数接收到对象,name和对象属性对应上即可:   2.springmvc不能直接通过form表单传递多个对象的list集合,要么采用ajax传递,要么采用封装了list属性的b ...

  8. 项目随笔之springmvc中freemark如何获取项目路径

    转载:http://blog.csdn.net/whatlookingfor/article/details/51538995 在SpringMVC框架中使用Freemarker试图时,要获取根路径的 ...

  9. 在springMVC的controller中获取request,response对象的一个方法

    ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttr ...

随机推荐

  1. Spring Boot系列——7步集成RabbitMQ

    RabbitMQ是一种我们经常使用的消息中间件,通过RabbitMQ可以帮助我们实现异步.削峰的目的. 今天这篇,我们来看看Spring Boot是如何集成RabbitMQ,发送消息和消费消息的.同时 ...

  2. The thumbprint of same asymmetric key is not same in 'SQL Server Connector for Microsoft Azure Key Vault' 1.0.4.0 and 'SQL Server Connector for Microsoft Azure Key

    https://support.microsoft.com/en-us/help/4470999/db-backup-problems-to-sql-server-connector-for-azur ...

  3. 再杀掉app之后 删除NSUserDefault存在本地的数据

    这两天在处理  app退出后删除本地数据  在appDelegate里的这个函数里设置发现进不去 - (void)applicationWillTerminate:(UIApplication*)ap ...

  4. Linux零基础入门第五课

    文件的基本操作(下) 文件属性 file命令 语法 >$ file file0 [file1 file2 ...] file命令用于确认文件的类型. 在Linux下,通常并不会严格按照文件扩展名 ...

  5. Golang学习教程

    字节跳动已经全线从Python转Golang了,可能开始学习Golang这门语言会觉得无所适从,和Java,C++,Python等都不大一样,但是用多了会发现这门语言设计的还是很优雅的,下面总结Gol ...

  6. Elasticsearch index fields 重命名

    reindex数据复制,重索引 POST _reindex { "source": { "index": "twitter" }, &quo ...

  7. 让windows 2003启动后直接进入桌面

    windows 2003启动后进入桌面需要解决的几个问题 1.如何去除掉 ctrl+alt+del的提示界面 2.如何设置自动登录的用户名密码 3.在异常启动时会出现关闭事件跟踪程序 也会导致不能直接 ...

  8. etl数据同步工具 kettle

    kellet使用 https://www.cnblogs.com/gala1021/p/7814712.html

  9. 从头配置,开发 cocos2dx 3.14.1

    要使用cocos2dx写一个麻将测试工具. 配置流程如下: 1. 下载安装最新版本的VS(VS2017): https://www.visualstudio.com/zh-hans/downloads ...

  10. game 角色相关记录

    GameServer启动 (role, misc, mail, offline)从共享内存中加载数据到m_mBlob中如果共享内存没有则从DB加载 主要是修改了同步共享内存,共享内存同步数据库{//r ...