SpringMVC-HandlerMapping
来源:互联网 发布:九连拍有什么软件 编辑:程序博客网 时间:2024/06/02 15:21
HandlerMapping
的作用根据request
找到对应的处理器Handler
,在HandlerMapping
接口中有一个唯一的方法getHanler
,HandlerMapping
接口的定义如下:
public interface HandlerMapping { HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception;}
方法的实现非常灵活,只要能根据request
返回HandlerExecutionChain
就可以了。
SpringMVC内置了很多HandlerMapping
的实现类,主体结构如下图所示:
从图中可以看出,AbstractHandlerMapping
是HandlerMapping
的最顶层抽象实现,在AbstractHandlerMapping
中定义了HandlerMapping
的整体结构,子类只需要通过默认方法提供初始值或具体的算法即可。
HandlerMapping
是SpringMVC处理请求过程中的一个重要组件,在SpringMVC启动时对容器中的HandlerMapping
进行初始化,初始化的位置在DispatcherServlet
的onRefresh()
方法中:
@Overrideprotected void onRefresh(ApplicationContext context) { //初始化组件策略 initStrategies(context);}protected void initStrategies(ApplicationContext context) { initMultipartResolver(context); initLocaleResolver(context); initThemeResolver(context); //初始化HandlerMapping initHandlerMappings(context); initHandlerAdapters(context); initHandlerExceptionResolvers(context); initRequestToViewNameTranslator(context); initViewResolvers(context); initFlashMapManager(context);}private void initHandlerMappings(ApplicationContext context) { this.handlerMappings = null; if (this.detectAllHandlerMappings) { // Find all HandlerMappings in the ApplicationContext, including ancestor contexts. //从Spring上下文中获取HandlerMapping类型的Bean Map<String, HandlerMapping> matchingBeans = BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerMapping.class, true, false); if (!matchingBeans.isEmpty()) { this.handlerMappings = new ArrayList<HandlerMapping>(matchingBeans.values()); // We keep HandlerMappings in sorted order. OrderComparator.sort(this.handlerMappings); } } else { try { //获取名称为handlerMapping的bean HandlerMapping hm = context.getBean(HANDLER_MAPPING_BEAN_NAME, HandlerMapping.class); this.handlerMappings = Collections.singletonList(hm); } catch (NoSuchBeanDefinitionException ex) { // Ignore, we'll add a default HandlerMapping later. } } // Ensure we have at least one HandlerMapping, by registering // a default HandlerMapping if no other mappings are found. if (this.handlerMappings == null) { //初始化默认的HandlerMapping,即BeanNameUrlHandlerMapping this.handlerMappings = getDefaultStrategies(context, HandlerMapping.class); if (logger.isDebugEnabled()) { logger.debug("No HandlerMappings found in servlet '" + getServletName() + "': using default"); } } }
从上面的代码中可以很清除的看见SpringMVC对HandlerMapping的初始化过程:
1.首先,根据detectAllHandlerMappings判断是否从容器中查找所有实现了HandlerMapping的bean。detectAllHandlerMappings默认为true,可以通过DispatcherServlet的初始化参数来修改默认值<init-param> <param-name>detectAllHandlerMappings</param-name> <param-value>false</param-value></init-param>2.如果detectAllHandlerMappings为false,则从容器中查找明为handlerMapping的bean作为HandlerMapping的唯一实例。3.如果以上两步都没有找到合适的handlerMapping,则会初始化默认的BeanNameUrlHandlerMapping
以上,是SpringMVC对HandlerMapping的初始化策略,下面在看一下HandlerMapping自身的初始化过程。
如上面所说,AbstractHandlerMapping
定义了HandlerMapping的整体结构,所以,HandlerMapping的初始化过程也在HandlerMapping中定义
,AbstractHandlerMapping
继承了WebApplicationObjectSupport
,AbstractHandlerMapping
的创建过程就是在initApplicationContext
中实现的。
@Overrideprotected void initApplicationContext() throws BeansException { extendInterceptors(this.interceptors); detectMappedInterceptors(this.mappedInterceptors); initInterceptors();}
在说明该方法前,先来看一下在AbstractHandlerMapping
中定义的三个与Interceptor有关的变量:
private final List<Object> interceptors = new ArrayList<Object>();private final List<HandlerInterceptor> adaptedInterceptors = new ArrayList<HandlerInterceptor>();private final List<MappedInterceptor> mappedInterceptors = new ArrayList<MappedInterceptor>();interceptors:用于配置SpringMVC中的拦截器,Interceptors并不会直接使用,而是通过initInterceptors方法按类型分配到mappedInterceptors和adaptedInterceptors中使用,interceptors只用于配置。mappedInterceptors:此类interceptor在使用时,需要与请求的url进行匹配,只有匹配成功在会被添加到getHandler返回值的HandlerExecutionChain中。adaptedInterceptors:这类interceptors不需要进行匹配,在getHandler中全部添加到返回值HandlerExecutionChain里面。
下面在看一下这三个方法:
protected void extendInterceptors(List<Object> interceptors) { }
extendInterceptors
方法用于给子类提供初始化interceptor的入口。
protected void detectMappedInterceptors(List<MappedInterceptor> mappedInterceptors) { mappedInterceptors.addAll( BeanFactoryUtils.beansOfTypeIncludingAncestors( getApplicationContext(), MappedInterceptor.class, true, false).values()); }
detectMapedInterceptors
方法从容器中查找所有Mapped
类型的bean,并放入
InterceptormappedInterceptors
中。
protected void initInterceptors() { if (!this.interceptors.isEmpty()) { for (int i = 0; i < this.interceptors.size(); i++) { Object interceptor = this.interceptors.get(i); if (interceptor == null) { throw new IllegalArgumentException("Entry number " + i + " in interceptors array is null"); } if (interceptor instanceof MappedInterceptor) { this.mappedInterceptors.add((MappedInterceptor) interceptor); } else { this.adaptedInterceptors.add(adaptInterceptor(interceptor)); } } } }
initInterceptors
方法将interceptors
里面所有包含的对象按照类型添加到mappedInterceptors
或adaptedInterceptors
总结一下:
HandlerMapping的初始化始于WebContextObjectSupport的initApplicationContext方法,这个方法的作用的初始化interceptor,interceptor主要分为两种,一种的mappedInterceptors,另一种是adaptedInterceptors,其中mappedInterptors在应用是要跟url进行匹配,而adapterInterceptors会被直接应用。
HandlerMapping
的入口方法是getHandler()
,在AbstractHandlerMapping
中,对这个方法进行了实现,同时,也是定义getHandler()
的主体逻辑,下面看一下:
@Overridepublic 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); } return getHandlerExecutionChain(handler, request);}
在getHandler()
中,做了两件事,第一是根据request
获取heandler
,这是HandlerMapping的主要作用,由getHandlerInternal()
完成
protected abstract Object getHandlerInternal(HttpServletRequest request) throws Exception;
但该方法是抽象方法,由子类实现。 getHandler()
做的第二件事是将Handler
和Interceptor
组装成HandlerExecutionChain
。
protected HandlerExecutionChain getHandlerExecutionChain(Object handler, HttpServletRequest request) { HandlerExecutionChain chain = (handler instanceof HandlerExecutionChain ? (HandlerExecutionChain) handler : new HandlerExecutionChain(handler)); chain.addInterceptors(getAdaptedInterceptors()); String lookupPath = this.urlPathHelper.getLookupPathForRequest(request); for (MappedInterceptor mappedInterceptor : this.mappedInterceptors) { if (mappedInterceptor.matches(lookupPath, this.pathMatcher)) { chain.addInterceptor(mappedInterceptor.getInterceptor()); } } return chain;}
在这个方法中,首先初始化一个HandlerExecutionChain
,然后将所有adaptedInterceptor添加到HandlerExecutionChain
,最后,根据url从mappedInterceptors
中过滤出需要的Interceptor并放入HandlerExecutionChain
中。
总结一下:
应用HandlerMapping的入口方法是getHandler,AbstractionHandlerMapping定义了getHandler的整体结构:1.获取Handler,这一步交给子类完成2.组装hander和interceptor为HandlerExecutionChain所有的adaptedInterceptor会被方法到HandlerExecutionChain,与url匹配的mappedInterceptor会被放入到HandlerExecutionChain中。
上面说的是AbstractHandlerMapping
的初始化过程和HandlerMapping
的使用入口的逻辑。下面详述一下HandlerMapping
的一个大分支:AbstractUrlHandlerMapping
。
AbstractUrlHandlerMapping
的大致原理是实现从url到Handler
的映射,映射关系存在在一个map中,所以,AbstractHandlerMapping
的主要工作就是:
1.初始化这个存放映射关系的map
2.从map中找到对应的Handler
作为getHandlerInternal()
的返回值。
先来看一下AbstractUrlHandlerMapping
中对getHandlerInternal()
的定义:
private final Map<String, Object> handlerMap = new LinkedHashMap<String, Object>();@Overrideprotected Object getHandlerInternal(HttpServletRequest request) throws Exception { String lookupPath = getUrlPathHelper().getLookupPathForRequest(request); //跟url从handlerMap中找到Handler Object handler = lookupHandler(lookupPath, request); if (handler == null) { // We need to care for the default handler directly, since we need to // expose the PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE for it as well. Object rawHandler = null; if ("/".equals(lookupPath)) { rawHandler = getRootHandler(); } if (rawHandler == null) { rawHandler = getDefaultHandler(); } if (rawHandler != null) { // Bean name or resolved handler? if (rawHandler instanceof String) { String handlerName = (String) rawHandler; rawHandler = getApplicationContext().getBean(handlerName); } validateHandler(rawHandler, request); //设置两个内置拦截器 handler = buildPathExposingHandler(rawHandler, lookupPath, lookupPath, null); } } return handler;}
总结一个:
AbstractUrlHandlerMapping的getHandlerInternal()主要做了两件事:1.根据url找到Handler2.位Handler设置两个内置拦截器,作用是将当前url匹配的pattern、匹配条件和url模板参数设置到request作用域中
在根据url获取handler的过程中,其实并不是简单是getByKey(url),在编写Controller
时,通常我们会通过模式匹配或者路径变量来映射url,此时就需要更复杂的匹配过程,来看一下lookupHandler()
是如何实现的:
protected Object lookupHandler(String urlPath, HttpServletRequest request) throws Exception { // 首先,直接根据url从handlerMap中获取 Object handler = this.handlerMap.get(urlPath); if (handler != null) { // Bean name or resolved handler? if (handler instanceof String) { String handlerName = (String) handler; handler = getApplicationContext().getBean(handlerName); } validateHandler(handler, request); return buildPathExposingHandler(handler, urlPath, urlPath, null); } // 如果没有获取到,按照模式匹配来找 List<String> matchingPatterns = new ArrayList<String>(); for (String registeredPattern : this.handlerMap.keySet()) { if (getPathMatcher().match(registeredPattern, urlPath)) { matchingPatterns.add(registeredPattern); } } String bestPatternMatch = null; Comparator<String> patternComparator = getPathMatcher().getPatternComparator(urlPath); if (!matchingPatterns.isEmpty()) { Collections.sort(matchingPatterns, patternComparator); //匹配过程中,可以有多个Handler,那么通过排序后,取优先级最高的一个 bestPatternMatch = matchingPatterns.get(0); } if (bestPatternMatch != null) { handler = this.handlerMap.get(bestPatternMatch); // Bean name or resolved handler? if (handler instanceof String) { String handlerName = (String) handler; handler = getApplicationContext().getBean(handlerName); } validateHandler(handler, request); String pathWithinMapping = getPathMatcher().extractPathWithinPattern(bestPatternMatch, urlPath); // There might be multiple 'best patterns', let's make sure we have the correct URI template variables // for all of them //此处处理匹配出多个且优先级相同的handler的情况 Map<String, String> uriTemplateVariables = new LinkedHashMap<String, String>(); for (String matchingPattern : matchingPatterns) { if (patternComparator.compare(bestPatternMatch, matchingPattern) == 0) { Map<String, String> vars = getPathMatcher().extractUriTemplateVariables(matchingPattern, urlPath); Map<String, String> decodedVars = getUrlPathHelper().decodePathVariables(request, vars); uriTemplateVariables.putAll(decodedVars); } } return buildPathExposingHandler(handler, bestPatternMatch, pathWithinMapping, uriTemplateVariables); } // No handler found... return null;}
总结一下:在根据url获取Handler的过程中1.首先,直接根据url从handlerMap中获取Handler2.如果没有找到,按照模式匹配来找到合适的Handler3.最后,呼应getHandlerInternal()方法,设置两个内置的InterceptorlookupHandler()返回的实际是HandlerExecutionChain,这也就与AbstractHandlerMapping中getExecutionChain的逻辑相呼应:HandlerExecutionChain chain = (handler instanceof HandlerExecutionChain ? (HandlerExecutionChain) handler : new HandlerExecutionChain(handler));**首先判断getHandlerInternal()方法返回的是否是一个HandlerExecutionChain,如果不是则创建。**
对于buildPathExposingHandler()
方法就是完成上面说的设置两个内置拦截器的功能,具体逻辑很简单,就不说了。
在应用上面的逻辑查找Handler
之前,一个重要的工作是对handlerMap进行初始化。handlerMap的初始化方法定义在AbstractUrlHandlerMapping
中,单具体的调用是由子类完成的。两个方法如下:
protected void registerHandler(String[] urlPaths, String beanName) throws BeansException, IllegalStateException { Assert.notNull(urlPaths, "URL path array must not be null"); for (String urlPath : urlPaths) { registerHandler(urlPath, beanName); }}protected void registerHandler(String urlPath, Object handler) throws BeansException, IllegalStateException { Assert.notNull(urlPath, "URL path must not be null"); Assert.notNull(handler, "Handler object must not be null"); Object resolvedHandler = handler; // Eagerly resolve handler if referencing singleton via name. if (!this.lazyInitHandlers && handler instanceof String) { String handlerName = (String) handler; if (getApplicationContext().isSingleton(handlerName)) { resolvedHandler = getApplicationContext().getBean(handlerName); } } Object mappedHandler = this.handlerMap.get(urlPath); if (mappedHandler != null) { if (mappedHandler != resolvedHandler) { throw new IllegalStateException( "Cannot map " + getHandlerDescription(handler) + " to URL path [" + urlPath + "]: There is already " + getHandlerDescription(mappedHandler) + " mapped."); } } else { if (urlPath.equals("/")) { if (logger.isInfoEnabled()) { logger.info("Root mapping to " + getHandlerDescription(handler)); } setRootHandler(resolvedHandler); } else if (urlPath.equals("/*")) { if (logger.isInfoEnabled()) { logger.info("Default mapping to " + getHandlerDescription(handler)); } setDefaultHandler(resolvedHandler); } else { this.handlerMap.put(urlPath, resolvedHandler); if (logger.isInfoEnabled()) { logger.info("Mapped URL path [" + urlPath + "] onto " + getHandlerDescription(handler)); } } }}
很简单,思路就是第一个方法调用第二个方法,第一个方法是将多个url映射到一个Handler
,另外需要注意的是,在registHandler
中,对/
和/*
做了特殊处理,这两个路径会被映射到rootHandler
上。
以上就是AbstractUrlHandlerMapping的主体逻辑
,总结一下:
AbstractHandlerMapping做了两件事:1.提供初始化handlerMap的入口-registerHander(),这也是与子类交互的接口。2.根据url从handlerMap中查找对应的Handler,此处需要注意的是AbstractUrlHandlerMapping对根路径做了特殊处理-映射到了rooterHandler。
SimpleUrlHandlerMapping
SimpleUrlHandlerMapping
是AbstractUrlHanderMapping
的一个子类,实现了从url到Controller
的映射。
由上文可知,AbstractUrlHandlerMapping
与SimpleUrlHandlerMapping
的交互接口是registerHandler
,所以,在SimpleUrlHandlerMapping
中定义了一个urlMap,这个map的作用是保存从url到Controller
的配置信息。
private final Map<String, Object> urlMap = new HashMap<String, Object>();
然后,、`SimpleUrlHandlerMapping
实现了WebApplicationObjectSupport
,并覆写了initApplicationContext()
方法
@Overridepublic void initApplicationContext() throws BeansException { super.initApplicationContext(); registerHandlers(this.urlMap);}
可以看出,首先调用父类方法完成对Interceptor的处理,然后调用了registerHandlers()
protected void registerHandlers(Map<String, Object> urlMap) throws BeansException { if (urlMap.isEmpty()) { logger.warn("Neither 'urlMap' nor 'mappings' set on SimpleUrlHandlerMapping"); } else { for (Map.Entry<String, Object> entry : urlMap.entrySet()) { String url = entry.getKey(); Object handler = entry.getValue(); // Prepend with slash if not already present. if (!url.startsWith("/")) { url = "/" + url; } // Remove whitespace from handler bean name. if (handler instanceof String) { handler = ((String) handler).trim(); } registerHandler(url, handler); } }}
从上面的代码可以看出,SimpleUrlHandlerMapping
的registerHandlers
方法主要是对配置进来的数据进行简单处理,然后调用了父类的registerHandler
方法。
AbstractHandlerMethodMapping
AbstractHandlerMethodMapping
是与AbstractUrlHandlerMapping
平行了另一种HandlerMapping
,将方法作为处理器Handler
,SpringMVC用HandlerMethod
来表示这个类型的Handler
。
从HandlerMapping
的结构图中可以看出,此类一共包含三个类:AbstractHandlerMethodMapping
,RequestMappingInfoHandlerMapping
和RequestMappingHandlerMapping
,这三个类依次继承。
AbstractHandlerMethodMapping
继承自AbstractHandlerMapping
,hook方法是getHandlerInternal()
,下面从 初始化和应用两个方面来看一下AbstractHandlerMethodMapping
。
AbstractHandlerMethodMapping的初始化
在AbstractHandlerMethodMapping
中有三个Map
private final Map<T, HandlerMethod> handlerMethodsprivate final MultiValueMap<String, T> urlMapprivate final MultiValueMap<String, HandlerMethod> nameMap
在这三个map中包含了一个泛型T,可以简单理解为查找HandlerMethod
时的匹配条件,从子类RequestMappingInfoHandlerMapping
的定义中就可以看出这个T的类型:
public abstract class RequestMappingInfoHandlerMapping extends AbstractHandlerMethodMapping<RequestMappingInfo> { ....}
对RequestMappingInfo和RequestCondition的说明放在后面。
下面看一下上面三个map的作用:
urlMap:存放请求的url与匹配HandlerMethod的RequestCondition之间的映射nameMap:存放Controleller的BeanName和RequestCondition之间的映射handlerMethods:存放RequestCondition和HandlerMethod之间的映射
这三个map中 urlMap
和nameMap
的类型是 MultiValueMap
,可以把多个value映射到一个key上,这个类型的数据结构从类定义中就可以很清楚的看出来:
public interface MultiValueMap<K, V> extends Map<K, List<V>> { ...}
这三个map是AbstractHandlerMethodMapping
最主要的容器,它的初始化主要就是对这个三个map中的内容进行初始化。
由于AbstractHandlerMethodMapping
实现了InitializingBean
接口,所以在启动springmvc时会自动调用afterPropertiesSet()
方法,初始化工作就在这个方法中完成的。
@Overridepublic void afterPropertiesSet() { initHandlerMethods();}protected void initHandlerMethods() { //从spring容器中获取所有bean的beanname String[] beanNames = (this.detectHandlerMethodsInAncestorContexts ? BeanFactoryUtils.beanNamesForTypeIncludingAncestors(getApplicationContext(), Object.class) : getApplicationContext().getBeanNamesForType(Object.class));//遍历所有BeanName for (String beanName : beanNames) { //判断Bean是否包含Controller或者RequestMapping注解 if (!beanName.startsWith(SCOPED_TARGET_NAME_PREFIX) && isHandler(getApplicationContext().getType(beanName))){ //将Bean初始化到上面的map detectHandlerMethods(beanName); } } handlerMethodsInitialized(getHandlerMethods()); }
在initHandlerMethods()
中主要做的是筛选出符合可以作为HandlerMethod条件的Bean,然后调用detectHandlerMethods()
将这些bean初始化到map中。
对于handlerMethodsInitialized()
方法,只是一个模板方法,且子类并没有使用,所以这个方法也就没有意义。
总结一下:
在AbstractHandlerMethodMapping中有三个map:urlMap,nameMap和handlerMethods,用来完成从url到RequestCondition,以及从RequestCondition到HandlerMethod的映射。AbstractHandlerMethodMapping实现了InitializingBean接口,启动容器时,调用afterPropertiesSet()方法完成初始化,初始化从initHandlerMethods()方法开始,首先,获取所有beanname,然后在根据beanname获取bean的实例,并判断是否符合作为HandlerMethod的条件,若符合则交给detectHandlerMethods()方法,完成最终的初始化。
再来看detectHandlerMethods()
方法:
protected void detectHandlerMethods(final Object handler) {//获取handler类型,此处的HandlerType仍然是类的class对象 Class<?> handlerType = (handler instanceof String ? getApplicationContext().getType((String) handler) : handler.getClass()); // Avoid repeated calls to getMappingForMethod which would rebuild RequestMappingInfo instances final Map<Method, T> mappings = new IdentityHashMap<Method, T>(); final Class<?> userType = ClassUtils.getUserClass(handlerType);//从clazz中找到符合条件的Method Set<Method> methods = HandlerMethodSelector.selectMethods(userType, new MethodFilter() { @Override public boolean matches(Method method) { T mapping = getMappingForMethod(method, userType); if (mapping != null) { //将符合条件的method和RequestMappingInfo添加到mappings, 在后面使用 mappings.put(method, mapping); return true; } else { return false; } } });//遍历所有符合条件的Method,并利用handler/method/requestCondition进行注册。 for (Method method : methods) { registerHandlerMethod(handler, method, mappings.get(method)); } }
从代码中可以看出,detectHandlerMethods()
方法主要的逻辑就是找出符合条件的Method,然后将其根据handler和requestcondtion进行注册。
protected void registerHandlerMethod(Object handler, Method method, T mapping) {//根据handler和Method创建HandlerMethod HandlerMethod newHandlerMethod = createHandlerMethod(handler, method);//根据requestcondition从容器中获取之前的HandlerMethod HandlerMethod oldHandlerMethod = this.handlerMethods.get(mapping); //如果原有的HandlerMethod和新的HandlerMethod不相等,则抛异常 if (oldHandlerMethod != null && !oldHandlerMethod.equals(newHandlerMethod)) { throw new IllegalStateException("Ambiguous mapping found. Cannot map '" + newHandlerMethod.getBean() + "' bean method \n" + newHandlerMethod + "\nto " + mapping + ": There is already '" + oldHandlerMethod.getBean() + "' bean method\n" + oldHandlerMethod + " mapped."); }//否则,在handlerMethods中建立新的映射关系 this.handlerMethods.put(mapping, newHandlerMethod);//将匹配的url与RequestCondition初始化到urlMap中 Set<String> patterns = getMappingPathPatterns(mapping); for (String pattern : patterns) { if (!getPathMatcher().isPattern(pattern)) { this.urlMap.add(pattern, mapping); } }//初始化nameMap if (this.namingStrategy != null) { String name = this.namingStrategy.getName(newHandlerMethod, mapping); updateNameMap(name, newHandlerMethod); } }
到此,AbstractHandlerMethodMapping
的初始化就完成了。
AbstractHandlerMethodMapping的应用
入口方法依然是getHandlerInternal()
@Overrideprotected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {//获取访问路径 String lookupPath = getUrlPathHelper().getLookupPathForRequest(request); //根据访问路径获取HandlerMethod HandlerMethod handlerMethod = lookupHandlerMethod(lookupPath, request); return (handlerMethod != null ? handlerMethod.createWithResolvedBean() : null); }
getHandlerInternal()
中最重要的一步就是lookupHandlerMethod()
protected HandlerMethod lookupHandlerMethod(String lookupPath, HttpServletRequest request) throws Exception { List<Match> matches = new ArrayList<Match>(); //根据url从urlMap中获取RequestCondition List<T> directPathMatches = this.urlMap.get(lookupPath); if (directPathMatches != null) { //如果获取到,添加到matches addMatchingMappings(directPathMatches, matches, request); } if (matches.isEmpty()) { // No choice but to go through all mappings...//如果不能直接获取到,则把所有能匹配的RequestCondition天添加到matches中 addMatchingMappings(this.handlerMethods.keySet(), matches, request); } if (!matches.isEmpty()) { //对matches进行排序,然后获取第一个作为bestMatch返回 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) { 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 { //如果仍然没有,则返回null return handleNoMatch(handlerMethods.keySet(), lookupPath, request); } }
总结一下:
AbstractHandlerMethodMapping的应用:1.获取请求路径2.根据请求路径找到HandlerMethod 分别从handlerMethods和urlMap中查找
- SpringMVC--HandlerMapping
- SpringMVC------handlerMapping
- SpringMVC-HandlerMapping
- springMVC(二)HandlerMapping
- SpringMVC handlerMapping和handlerAdapter
- springmvc handlerMapping和handleradapt
- SpringMVC中HandlerMapping源码
- SpringMVC分析--------HandlerMapping
- springMVC源码--HandlerMapping(一)
- SpringMVC-几种HandlerMapping介绍
- SpringMVC三种handlerMapping配置
- SpringMVC的3种HandlerMapping
- SpringMVC 流程(2)-- HandlerMapping
- springmvc源码阅读笔记 --HandlerMapping
- 10.SpringMVC 请求处理 - HandlerMapping
- SpringMVC的四种HandlerMapping
- SpringMVC中的处理器映射(handlerMapping)
- springMVC源码分析--HandlerMapping(一)
- Shell 命令之 awk
- mac环境安装mongo
- UVA-1588 Kickdown
- Tensorflow体验: 搭建 3D CNN
- 从0移植uboot (二) _uboot启动流程分析
- SpringMVC-HandlerMapping
- 设计模式之单例模式
- 逻辑斯蒂回归(LogisticRegression)sklearn的一个例子中文解释
- 对于最常用的排序快速排序的思考
- 你画我猜题目库
- Java界面中使用SwingWorker
- Android Studio插件合集
- 应用在后台被强杀的解决方案
- Android java.lang.UnsatisfiedLinkError