HandlerMapping接口只有一個方法app
HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception;
就是根據Reuqest返回HandlerExecutionChain,看名字就知道是一個處理鏈,包含多個Interceptor和一個Handler。cors
AbstractHandlerMapping是HanlderMapping的默認實現類。是一個模板方法(Spring 底層大代碼大量使用模板方法)。ide
@Override protected void initApplicationContext() throws BeansException { extendInterceptors(this.interceptors); detectMappedInterceptors(this.adaptedInterceptors); initInterceptors(); }
deleteMappedIntercptors方法的左右就是把ApplicationContext中全部類型爲MappedInterceptor的bean加入到adaptedIntercptors這個成員變量中函數
protected void detectMappedInterceptors(List<HandlerInterceptor> mappedInterceptors) { mappedInterceptors.addAll( BeanFactoryUtils.beansOfTypeIncludingAncestors( getApplicationContext(), MappedInterceptor.class, true, false).values()); }
initInterceptors()函數的做用就是把成員變量interceptors中的interceptor加入到adaptedInterceptors成員變量中去,若是是WebRequestInterceptor則轉換爲對應的adapter類,代碼以下ui
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"); } this.adaptedInterceptors.add(adaptInterceptor(interceptor)); } } }
protected HandlerInterceptor adaptInterceptor(Object interceptor) { if (interceptor instanceof HandlerInterceptor) { return (HandlerInterceptor) interceptor; } else if (interceptor instanceof WebRequestInterceptor) { return new WebRequestHandlerInterceptorAdapter((WebRequestInterceptor) interceptor); } else { throw new IllegalArgumentException("Interceptor type not supported: " + interceptor.getClass().getName()); } }
@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); } 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; }
主要作了2件事:this
AbstractHandleMapping是一個模板方法,子類須要實現getHandlerInternal。下面介紹2個主要實現類AbstractUrlHandleMapping和AbstractHandleMethodMapping。url
從名字能夠猜到,AbstractUrlHandleMapping是經過url來匹配對應的Handler。AbstractUrlHandleMapping依然是一個抽象類。getHandlerInternal代碼:spa
/** * 根據request的url查詢對應的handler */ @Override protected Object getHandlerInternal(HttpServletRequest request) throws Exception { //查找url地址,有多是servlet的url,也有多是Spring Mvc定義的url String lookupPath = getUrlPathHelper().getLookupPathForRequest(request); //經過url查找對應的Handler Object handler = lookupHandler(lookupPath, request); //若是找不到對應的handler if (handler == null) { // 特殊狀況,若是查詢地址爲"/",則判斷是否用rootHandler,若是沒有就設置爲defaultHandler Object rawHandler = null; if ("/".equals(lookupPath)) { rawHandler = getRootHandler(); } if (rawHandler == null) { rawHandler = getDefaultHandler(); } if (rawHandler != null) { // 若是是字符串,則從ApplicationConetxt中獲取對應的bean if (rawHandler instanceof String) { String handlerName = (String) rawHandler; rawHandler = getApplicationContext().getBean(handlerName); } //模板方法,驗證Handler validateHandler(rawHandler, request); //返回HandlerExecutionChain類型,會註冊2個interceptor //PathExposingHandlerInterceptor和UriTemplateVariablesHandlerInterceptor handler = buildPathExposingHandler(rawHandler, lookupPath, lookupPath, null); } } if (handler != null && logger.isDebugEnabled()) { logger.debug("Mapping [" + lookupPath + "] to " + handler); } else if (handler == null && logger.isTraceEnabled()) { logger.trace("No handler mapping found for [" + lookupPath + "]"); } return handler; }
主要作了一下幾件事:debug
- 根據request生成查詢handler的URL
- 根據url獲取對應的handler
- 若是handler沒有在map中查到,則使用默認的handler。
方法目的就是根據url 查找對應的Handler,可是在url匹配的時候每每會有"/test/*"或者Path變量「/test/{id}」這樣的狀況,這樣就沒法經過url地址直接從map中獲取對應的handler。code
protected Object lookupHandler(String urlPath, HttpServletRequest request) throws Exception { // 可否直接找到 Object handler = this.handlerMap.get(urlPath); if (handler != null) { // 若是是字符串從ApplicationContext中直接獲取 if (handler instanceof String) { String handlerName = (String) handler; handler = getApplicationContext().getBean(handlerName); } // 模板方法,驗證handler validateHandler(handler, request); //返回HandlerExecutionChain類型,會註冊2個interceptor //PathExposingHandlerInterceptor和UriTemplateVariablesHandlerInterceptor 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); } else if (useTrailingSlashMatch()) { if (!registeredPattern.endsWith("/") && getPathMatcher().match(registeredPattern + "/", urlPath)) { matchingPatterns.add(registeredPattern +"/"); } } } //根據order找出優先級坐高的 String bestPatternMatch = null; Comparator<String> patternComparator = getPathMatcher().getPatternComparator(urlPath); if (!matchingPatterns.isEmpty()) { Collections.sort(matchingPatterns, patternComparator); if (logger.isDebugEnabled()) { logger.debug("Matching patterns for request [" + urlPath + "] are " + matchingPatterns); } bestPatternMatch = matchingPatterns.get(0); } if (bestPatternMatch != null) { handler = this.handlerMap.get(bestPatternMatch); if (handler == null) { Assert.isTrue(bestPatternMatch.endsWith("/")); handler = this.handlerMap.get(bestPatternMatch.substring(0, bestPatternMatch.length() - 1)); } if (handler instanceof String) { String handlerName = (String) handler; handler = getApplicationContext().getBean(handlerName); } validateHandler(handler, request); String pathWithinMapping = getPathMatcher().extractPathWithinPattern(bestPatternMatch, urlPath); // 這裏是處理當有多個url和最優的path是同一優先級的,那麼從裏面獲取地址變量,加入到uriTemplateVariables中 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); } //找不到對應的handler return null; }
這個函數主要完成了幾下幾件事
- url能直接從map中獲取的則直接獲取
- 不然經過路徑pattern去匹配url
- 從全部匹配到handler查找出優先級最高的
- 若是有多個同最優先級的,則查看裏面是否有pathVariable
- 找到任意的Handler則加入2個特殊的interceptor
上面全部的能成功找到對應的handler後,都會調用這個方法。這兒方法就是在handler的基礎上,加入2個interceptor,返回一個HandlerExecutionChain
protected Object buildPathExposingHandler(Object rawHandler, String bestMatchingPattern, String pathWithinMapping, Map<String, String> uriTemplateVariables) { HandlerExecutionChain chain = new HandlerExecutionChain(rawHandler); chain.addInterceptor(new PathExposingHandlerInterceptor(bestMatchingPattern, pathWithinMapping)); if (!CollectionUtils.isEmpty(uriTemplateVariables)) { chain.addInterceptor(new UriTemplateVariablesHandlerInterceptor(uriTemplateVariables)); } return chain; }
這2個interceptor的做用就是當前匹配的url、匹配條件和url模板參數設置到request的attribute裏面
上面一直說的經過url從map中獲取對應的Handler,這個map是成員變量
private final Map<String, Object> handlerMap = new LinkedHashMap<String, Object>();
這個map的初始化是在registerHandler方法,這個方法比較功能比較簡單,參數分別是url和handler,而後把url和handler放入map中,再作一些重複檢查和特殊handler(roothandler)的設置。url和handler從哪裏來,則又是子類提供處理具體的邏輯來調用這個方法。
到這裏,關於怎麼經過url來獲取handler已經解決了,下面就是url和handler是怎麼註冊到handlermap中的,其中大部分子類都被@Deprecated標記,
這個類很是簡單,就是給定參數map,註冊到handlermap中
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); } } }
如今來看看AbstractHandlerMapping的另一個繼承 AbstractHandlerMethodMapping
AbstractHandlerMethodMapping從名字就能夠看出,是把一個方法做爲一個handler。而且繼承體系也十分清晰。分析的順序和AbstractUrlHandleMapping相似,首先仍是先分析一下getHandlerInternal這個方法
@Override protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception { String lookupPath = getUrlPathHelper().getLookupPathForRequest(request); if (logger.isDebugEnabled()) { logger.debug("Looking up handler method for path " + lookupPath); } this.mappingRegistry.acquireReadLock(); try { HandlerMethod handlerMethod = lookupHandlerMethod(lookupPath, request); if (logger.isDebugEnabled()) { if (handlerMethod != null) { logger.debug("Returning handler method [" + handlerMethod + "]"); } else { logger.debug("Did not find handler method for [" + lookupPath + "]"); } } return (handlerMethod != null ? handlerMethod.createWithResolvedBean() : null); } finally { this.mappingRegistry.releaseReadLock(); } }
看起來和AbstractUrlHandleMapping相似,只不過AbstractUrlHandleMapping中的handler是一個bean,而AbstractHandlerMethodMapping的handler是一個Method
初始化方法initHandlerMethods:
protected void initHandlerMethods() { //獲取全部beanName String[] beanNames = (this.detectHandlerMethodsInAncestorContexts ? BeanFactoryUtils.beanNamesForTypeIncludingAncestors(getApplicationContext(), Object.class) : getApplicationContext().getBeanNamesForType(Object.class)); for (String beanName : beanNames) { //beanName是以scopedTarget.開頭的,則不用戶Handler Method if (!beanName.startsWith(SCOPED_TARGET_NAME_PREFIX)) { Class<?> beanType = null; try { beanType = getApplicationContext().getType(beanName); } catch (Throwable ex) { ... } // isHandler模板方法,由子類去判斷改bean是否註冊 if (beanType != null && isHandler(beanType)) { //註冊到HandlerMethod detectHandlerMethods(beanName); } } } //初始化HandlerMethod handlerMethodsInitialized(getHandlerMethods()); }
detectHandlerMethods,就是註冊handlerMethod。具體說明看註解
protected void detectHandlerMethods(final Object handler) { Class<?> handlerType = (handler instanceof String ? getApplicationContext().getType((String) handler) : handler.getClass()); final Class<?> userType = ClassUtils.getUserClass(handlerType); //查找該handler中的method及其對應的條件(參照@RequestMapping中的參數) Map<Method, T> methods = MethodIntrospector.selectMethods(userType, new MethodIntrospector.MetadataLookup<T>() { @Override public T inspect(Method method) { return getMappingForMethod(method, userType); } }); for (Map.Entry<Method, T> entry : methods.entrySet()) { Method invocableMethod = AopUtils.selectInvocableMethod(entry.getKey(), userType); T mapping = entry.getValue(); registerHandlerMethod(handler, invocableMethod, mapping); } }
- isHandler 是一個模板方法,由子類去判斷改bean是不是一個handler。
- getMappingForMethod也是一個模板方法,判斷一個類中Method方法的相關條件信息
- detectHandlerMethods是在傳入的beanName對應的bean中查找handlerMethod,而後註冊
- handlerMethodsInitialized 是一個預留方法,裏面沒有作任何事,若是咱們自定義一個HandlerMapping有須要的話能夠重寫
RequestMappingHandlerMapping繼承AbstractHandlerMethodMapping,首先看兩個模板方法
isHandler,就是判斷是否有Controller或者RequestMapping註解。
@Override protected boolean isHandler(Class<?> beanType) { return (AnnotatedElementUtils.hasAnnotation(beanType, Controller.class) || AnnotatedElementUtils.hasAnnotation(beanType, RequestMapping.class)); }
getMappingForMethod這個方法就是根據傳入的函數,返回一個RequestMappingInfo (也就是@RequestMapping中的參數信息)
@Override protected RequestMappingInfo getMappingForMethod(Method method, Class<?> handlerType) { RequestMappingInfo info = createRequestMappingInfo(method); if (info != null) { RequestMappingInfo typeInfo = createRequestMappingInfo(handlerType); if (typeInfo != null) { info = typeInfo.combine(info); } } return info; }
這樣,AbstractHandlerMethodMapping的就能經過一個url能夠找出對應MethodHandler,