springMVC(五): 通过 HandlerMapping 获取 HandlerExecutionChain
请求具体过程
一、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的更多相关文章
- java:JavaScript2:(setTimeout定时器,history.go()前进/后退,navigator.userAgent判断浏览器,location.href,五种方法获取标签属性,setAttribute,innerHTML,三种方法获取form表单信息,JS表单验证,DOM对象,form表单操作)
1.open,setTimeout,setInterval,clearInterval,clearTimeout <!DOCTYPE> <html> <head> ...
- SpringMVC请求参数的获取方式
一.GET请求参数获取 1. 通过HttpServletRequest获取参数 2. 直接方法参数获取 3. RequestParam注解方式获取请求参数 4. Bean方式获取参数 5. Model ...
- SpringMVC工作原理 : HandlerMapping和HandlerAdapter
一.HandlerMapping 作用是根据当前请求的找到对应的 Handler,并将 Handler(执行程序)与一堆 HandlerInterceptor(拦截器)封装到 HandlerExecu ...
- SpringMVC(关于HandlerMapping执行流程原理分析)
请求过来先碰见中央调度器(前端调度器) //Determine handler for the current request; 对当前请求决定交给哪个handler, 当前请求地址过来 处理器执行链 ...
- springmvc(五) 数据回显与自定义异常处理器
这章讲解一下springmvc的数据回显和自定义异常处理器的使用,两个都很简单 --WH 一.数据回显技术 Springmvc默认支持对pojo类型的数据回显,默认不支持简单类型的数据回显 1.1.什 ...
- SpringMVC请求使用@PathVariable获取文件名称并且文件名中存在.导致路径被截取的问题
在SpringMVC中,当使用@pathVariable通过Get请求获取路径名称时,如果路径名称上存在小数点,则获取不到小数点后面的内容,会被Spring截取. 比如我获取某一文件,路径是local ...
- SpringMVC传递参数和获取参数以及返回数据
1.传递form表单,参数接收到对象,name和对象属性对应上即可: 2.springmvc不能直接通过form表单传递多个对象的list集合,要么采用ajax传递,要么采用封装了list属性的b ...
- 项目随笔之springmvc中freemark如何获取项目路径
转载:http://blog.csdn.net/whatlookingfor/article/details/51538995 在SpringMVC框架中使用Freemarker试图时,要获取根路径的 ...
- 在springMVC的controller中获取request,response对象的一个方法
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttr ...
随机推荐
- PHP会员找回密码功能实现实例介绍
设置思路 1.用户注册时需要提供一个E-MAIL邮箱,目的就是用该邮箱找回密码. 2.当用户忘记密码或用户名时,点击登录页面的“找回密码”超链接,打开表单,并输入注册用的E-MAIL邮箱,提交. 3. ...
- asp.net中WebResponse 跨域访问示例
前两天,一个朋友让我帮他写这样一个程序:在asp.net里面访问asp的页面,把数据提交对方的数据库后,根据返回的值(返回值为:OK或ERROR),如果为OK再把填入本地数据库.当时,想当然,觉得很简 ...
- 18.翻译系列:EF 6 Code-First 中的Seed Data(种子数据或原始测试数据)【EF 6 Code-First系列】
原文链接:https://www.entityframeworktutorial.net/code-first/seed-database-in-code-first.aspx EF 6 Code-F ...
- hive SQL 行转列 和 列转行
一.行转列的使用 1.问题 hive如何将 a b 1a b 2a b 3c d 4c d ...
- Atitit 管理的模式扁平化管理 金字塔 直线型管理 垂直管理 水平管理 矩阵式管理 网状式样管理 多头管理 双头管理
Atitit 管理的模式扁平化管理 金字塔 直线型管理 垂直管理 水平管理 矩阵式管理 网状式样管理 多头管理 双头管理 1.1. 矩阵管理 1 1.2. 相关信息 矩阵的历史 1 1.3. 基于“ ...
- 基于Python37配置图片文字识别
以管理员权限打开cmd控制台. 1.如何安装PIL 输入下面命令:pip install Pillow 参考:https://www.cnblogs.com/mrgavin/p/8177841.htm ...
- hdoj:2055
#include <iostream> #include <string> using namespace std; bool islower(char ch) { if (c ...
- ZipUtil
/* * To change this license header, choose License Headers in Project Properties. * To change this t ...
- shell md5sum
md5sum out.a echo "fd_limit=$(ulimit -n), fd_used=$(ll /proc/4741/fd | wc -l)" 需找句柄,及fd ...
- 项目中phpexcel的基本用法
前提:要下载PHPEXCEL库文件 如:phpexcel官方下载 ,本人使用下载 情形一:对于将数据写入EXCEL表中的用法 header("content-type:text/htm ...