以前咱們springmvc原理篇裏已經介紹過,從springmvc核心處理器DispatcherServlet派遣請求的時候,首先會將請求包裝,這就是咱們這邊介紹的HandlerMappingjava
在springmvc源碼介紹中咱們知道,HandlerMapping是一個處理對象映射和映射對應的處理程序的一箇中間體,它也能夠由開發者本身去實現,可是咱們通常沒有這個必要,由於springmvc框架已經給咱們提供了足夠的映射處理器給咱們,一般在初始化咱們的web項目的時候,springmvc會初始化2個處理器:org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping、org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping,其中RequestMappingHandlerMapping即可以處理咱們在Controller中帶@RequestMapping的方法,HandlerMapping能夠直接實現攔截器,可是不會這麼作,一般HandlerMapping都會用一個叫HandlerExecutionChain的東西給包裝起來,而HandlerExecutionChain則引入了HandlerInterceptor(攔截器),在包裝類中,springmvc已經幫咱們處理好了映射對應的handler(處理方法)和攔截器web
DispatcherServlet中首先給當前請求指定對應的HandlerExecutionChainspring
源碼2.2.1mvc
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception { HttpServletRequest processedRequest = request; HandlerExecutionChain mappedHandler = null; boolean multipartRequestParsed = false; WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request); try { ModelAndView mv = null; Exception dispatchException = null; try { processedRequest = checkMultipart(request); multipartRequestParsed = (processedRequest != request); // Determine handler for the current request.(給當前請求指派對應的處理程序) mappedHandler = getHandler(processedRequest); if (mappedHandler == null || mappedHandler.getHandler() == null) { noHandlerFound(processedRequest, response); return; } //省略代碼 } }
DispatcherServlet提供循環HandlerMapping的方法,將請求包裝app
源碼2.2.2cors
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() + "'"); } HandlerExecutionChain handler = hm.getHandler(request); if (handler != null) { return handler; } } return null; }
在AbstractHandlerMapping(抽象HandlerMapping)中處理了HandlerMapping對應的處理程序,加入攔截器框架
源碼2.2.3async
@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; }
那麼問題來了?HandlerMapping如何處理帶@RequestMapping的方法?ide
springmvc很機制,直接將兩個類的字母鏈接起來造成一個叫RequestMappingHandlerMapping,RequestMappingHandlerMapping依賴RequestMappingInfoHandlerMapping、RequestMappingInfoHandlerMapping依賴AbstractHandlerMethodMapping(看依賴圖),在AbstractHandlerMethodMapping中的一個內部類MappingRegistry中,經過註冊方法,直接將ui
@RequestMappng中包含的信息RequestMappingInfo和HandlerMethod經過LinkedHashMap(key-value)方式鏈接,也就是說有了RequestMapping(RequestMappingInfo)就能獲得HandlerMethod(看源碼2.2.7)HandlerMethod包裝了執行類、執行方法、參數、橋接處理器
源碼2.2.4
@Override protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception { //獲取url String lookupPath = getUrlPathHelper().getLookupPathForRequest(request); if (logger.isDebugEnabled()) { logger.debug("Looking up handler method for path " + lookupPath); } this.mappingRegistry.acquireReadLock(); try { //根據url獲取HandlerMethod 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(); } }
源碼2.2.5
//查找當前請求的最優處理方法。若是找到多個匹配,選擇最佳匹配。 protected HandlerMethod lookupHandlerMethod(String lookupPath, HttpServletRequest request) throws Exception { List<Match> matches = new ArrayList<Match>(); //mappingRegistry註冊器 List<T> directPathMatches = this.mappingRegistry.getMappingsByUrl(lookupPath); if (directPathMatches != null) { addMatchingMappings(directPathMatches, matches, request); } if (matches.isEmpty()) { // 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); } }
源碼2.2.6
註冊器註冊了映射和HandlerMethod的關係,而且使得後續適配器中獲得適配
源碼2.2.7
public void register(T mapping, Object handler, Method method) { this.readWriteLock.writeLock().lock(); try { HandlerMethod handlerMethod = createHandlerMethod(handler, method); assertUniqueMethodMapping(handlerMethod, mapping); if (logger.isInfoEnabled()) { logger.info("Mapped \"" + mapping + "\" onto " + handlerMethod); } //將requestMappingInfo和handlerMethod綁定 this.mappingLookup.put(mapping, handlerMethod); List<String> directUrls = getDirectUrls(mapping); for (String url : directUrls) { this.urlLookup.add(url, mapping); } String name = null; if (getNamingStrategy() != null) { name = getNamingStrategy().getName(handlerMethod, mapping); addMappingName(name, handlerMethod); } CorsConfiguration corsConfig = initCorsConfiguration(handler, method, mapping); if (corsConfig != null) { this.corsLookup.put(handlerMethod, corsConfig); } this.registry.put(mapping, new MappingRegistration<T>(mapping, handlerMethod, directUrls, name)); } finally { this.readWriteLock.writeLock().unlock(); } }
到此爲止,springmvc已經將請求包裝處理好,也就是對應第一張原理圖中的以下標記是二、3的部分
期待下一章HandlerAdapter