在初始化完成時,全部的handlerMapping都已經被加載,handlerMapping存儲着HTTP請求對應的映射數據,每個handlerMapping持有從URL請求到Controller的映射。java
這裏以SimpleUrlHandlerMapping爲例來分析它的設計與實現。在SimpleUrlHandlerMapping中,定義了一個map來維持映射關係,即URL請求和控制器對應關係,spring
是SpringMVC應用能夠根據HTTP請求肯定對一個對應的Controller,具體來講,這些映射關係是經過接口類HandlerMapping來封裝,在HandlerMapping接口中定義了一個getHandler方法,app
經過這個方法,能夠得到與HTTP請求對應的HandlerExecutionChain,在這個HandlerExecutionChain中,封裝具體的Controller對象。async
SimpleUrlHandlerMapping中的urlMap:ide
public class SimpleUrlHandlerMapping extends AbstractUrlHandlerMapping { //url和controller映射的map private final Map<String, Object> urlMap = new HashMap<String, Object>();
HandlerMapping中的getHandlerpost
public interface HandlerMapping { //省略。。。 HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception; }
接下來,看一下HandlerExecutionChain的實現。ui
public class HandlerExecutionChain { private static final Log logger = LogFactory.getLog(HandlerExecutionChain.class); private final Object handler;//處理對象,也就是controller對象 private HandlerInterceptor[] interceptors;//攔截器 private List<HandlerInterceptor> interceptorList;//攔截器 private int interceptorIndex = -1; /** * Create a new HandlerExecutionChain. * @param handler the handler object to execute */ public HandlerExecutionChain(Object handler) { this(handler, (HandlerInterceptor[]) null); } /** * Create a new HandlerExecutionChain. * @param handler the handler object to execute * @param interceptors the array of interceptors to apply * (in the given order) before the handler itself executes *///初始化 public HandlerExecutionChain(Object handler, HandlerInterceptor... interceptors) { if (handler instanceof HandlerExecutionChain) { HandlerExecutionChain originalChain = (HandlerExecutionChain) handler; this.handler = originalChain.getHandler(); this.interceptorList = new ArrayList<HandlerInterceptor>(); CollectionUtils.mergeArrayIntoCollection(originalChain.getInterceptors(), this.interceptorList); CollectionUtils.mergeArrayIntoCollection(interceptors, this.interceptorList); } else { this.handler = handler; this.interceptors = interceptors; } } /** * Return the handler object to execute. * @return the handler object *///獲取handler,本質就是controller對象 public Object getHandler() { return this.handler; } //添加攔截器 public void addInterceptor(HandlerInterceptor interceptor) { initInterceptorList().add(interceptor); } //添加多個攔截器 public void addInterceptors(HandlerInterceptor... interceptors) { if (!ObjectUtils.isEmpty(interceptors)) { initInterceptorList().addAll(Arrays.asList(interceptors)); } } private List<HandlerInterceptor> initInterceptorList() { if (this.interceptorList == null) { this.interceptorList = new ArrayList<HandlerInterceptor>(); if (this.interceptors != null) { // An interceptor array specified through the constructor this.interceptorList.addAll(Arrays.asList(this.interceptors)); } } this.interceptors = null; return this.interceptorList; } /** * Return the array of interceptors to apply (in the given order). * @return the array of HandlerInterceptors instances (may be {@code null}) */ public HandlerInterceptor[] getInterceptors() { if (this.interceptors == null && this.interceptorList != null) { this.interceptors = this.interceptorList.toArray(new HandlerInterceptor[this.interceptorList.size()]); } return this.interceptors; } /** * Apply preHandle methods of registered interceptors. * @return {@code true} if the execution chain should proceed with the * next interceptor or the handler itself. Else, DispatcherServlet assumes * that this interceptor has already dealt with the response itself. *///執行以前調用攔截器 boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception { HandlerInterceptor[] interceptors = getInterceptors(); if (!ObjectUtils.isEmpty(interceptors)) { for (int i = 0; i < interceptors.length; i++) { HandlerInterceptor interceptor = interceptors[i]; if (!interceptor.preHandle(request, response, this.handler)) { triggerAfterCompletion(request, response, null); return false; } this.interceptorIndex = i; } } return true; } /** * Apply postHandle methods of registered interceptors. *///執行以後調用攔截器 void applyPostHandle(HttpServletRequest request, HttpServletResponse response, ModelAndView mv) throws Exception { HandlerInterceptor[] interceptors = getInterceptors(); if (!ObjectUtils.isEmpty(interceptors)) { for (int i = interceptors.length - 1; i >= 0; i--) { HandlerInterceptor interceptor = interceptors[i]; interceptor.postHandle(request, response, this.handler, mv); } } } /** * Trigger afterCompletion callbacks on the mapped HandlerInterceptors. * Will just invoke afterCompletion for all interceptors whose preHandle invocation * has successfully completed and returned true. *///調用攔截器的afterCompletion方法 void triggerAfterCompletion(HttpServletRequest request, HttpServletResponse response, Exception ex) throws Exception { HandlerInterceptor[] interceptors = getInterceptors(); if (!ObjectUtils.isEmpty(interceptors)) { for (int i = this.interceptorIndex; i >= 0; i--) { HandlerInterceptor interceptor = interceptors[i]; try { interceptor.afterCompletion(request, response, this.handler, ex); } catch (Throwable ex2) { logger.error("HandlerInterceptor.afterCompletion threw exception", ex2); } } } } /** * Apply afterConcurrentHandlerStarted callback on mapped AsyncHandlerInterceptors. */ void applyAfterConcurrentHandlingStarted(HttpServletRequest request, HttpServletResponse response) { HandlerInterceptor[] interceptors = getInterceptors(); if (!ObjectUtils.isEmpty(interceptors)) { for (int i = interceptors.length - 1; i >= 0; i--) { if (interceptors[i] instanceof AsyncHandlerInterceptor) { try { AsyncHandlerInterceptor asyncInterceptor = (AsyncHandlerInterceptor) interceptors[i]; asyncInterceptor.afterConcurrentHandlingStarted(request, response, this.handler); } catch (Throwable ex) { logger.error("Interceptor [" + interceptors[i] + "] failed in afterConcurrentHandlingStarted", ex); } } } } } /** * Delegates to the handler's {@code toString()}. */ @Override public String toString() { if (this.handler == null) { return "HandlerExecutionChain with no handler"; } StringBuilder sb = new StringBuilder(); sb.append("HandlerExecutionChain with handler [").append(this.handler).append("]"); if (!CollectionUtils.isEmpty(this.interceptorList)) { sb.append(" and ").append(this.interceptorList.size()).append(" interceptor"); if (this.interceptorList.size() > 1) { sb.append("s"); } } return sb.toString(); } }
下面是攔截器的執行圖this
對應的applyPreHandle和applyPostHandle方法代碼以下:url
/** * Apply preHandle methods of registered interceptors. * @return {@code true} if the execution chain should proceed with the * next interceptor or the handler itself. Else, DispatcherServlet assumes * that this interceptor has already dealt with the response itself. */ boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception { HandlerInterceptor[] interceptors = getInterceptors(); if (!ObjectUtils.isEmpty(interceptors)) { for (int i = 0; i < interceptors.length; i++) { HandlerInterceptor interceptor = interceptors[i]; if (!interceptor.preHandle(request, response, this.handler)) { triggerAfterCompletion(request, response, null); return false; } this.interceptorIndex = i; } } return true; } /** * Apply postHandle methods of registered interceptors. */ void applyPostHandle(HttpServletRequest request, HttpServletResponse response, ModelAndView mv) throws Exception { HandlerInterceptor[] interceptors = getInterceptors(); if (!ObjectUtils.isEmpty(interceptors)) { for (int i = interceptors.length - 1; i >= 0; i--) { HandlerInterceptor interceptor = interceptors[i]; interceptor.postHandle(request, response, this.handler, mv); } } }
回到SimpleUrlHandlerMapping中,有一個initApplicationContext方法spa
/** * Calls the {@link #registerHandlers} method in addition to the * superclass's initialization. */ @Override public void initApplicationContext() throws BeansException { super.initApplicationContext(); registerHandlers(this.urlMap); }
繼續看看registerHandlers方法,註冊Handler
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); } } }
AbstractUrlHandlerMapping對handler的註冊
/** * Register the specified handler for the given URL path. * @param urlPath the URL the bean should be mapped to * @param handler the handler instance or handler bean name String * (a bean name will automatically be resolved into the corresponding handler bean) * @throws BeansException if the handler couldn't be registered * @throws IllegalStateException if there is a conflicting handler registered */ 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);//直接從spring容器中獲取handler } } Object mappedHandler = this.handlerMap.get(urlPath);//從map中獲取handler 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);//url是"/",將其設置爲根handler } else if (urlPath.equals("/*")) { if (logger.isInfoEnabled()) { logger.info("Default mapping to " + getHandlerDescription(handler)); } setDefaultHandler(resolvedHandler);//默認handler } else { this.handlerMap.put(urlPath, resolvedHandler);//註冊handler,url爲key,controller爲value的map if (logger.isInfoEnabled()) { logger.info("Mapped URL path [" + urlPath + "] onto " + getHandlerDescription(handler)); } } } }
有了上面的配置好了Url和Controller的映射關係,爲SpringMVC響應HTTP請求準備好了基礎的映射數據,至此SpringMVC就能夠等待HTTP的請求的到來。
當請求來時,首先AbstractHandlerMapping的getHandler被調用,方法參數是request
@Override public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception { Object handler = getHandlerInternal(request); if (handler == null) {//爲空走默認的handler handler = getDefaultHandler(); } if (handler == null) { return null; } // Bean name or resolved handler? if (handler instanceof String) { String handlerName = (String) handler;//從spring容器中獲取 handler = getApplicationContext().getBean(handlerName); } return getHandlerExecutionChain(handler, request);//把handler封裝到HandlerExecutionChain中並加上攔截器 }
封裝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; }
上面的getHnadler會調用getHandlerInternal
protected Object getHandlerInternal(HttpServletRequest request) throws Exception { String lookupPath = getUrlPathHelper().getLookupPathForRequest(request); 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); } } 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; }
這裏調用的是lookupHandler方法,在來看一下這個方法。
protected Object lookupHandler(String urlPath, HttpServletRequest request) throws Exception { // Direct match? 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); } // Pattern match? 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); if (logger.isDebugEnabled()) { logger.debug("Matching patterns for request [" + urlPath + "] are " + matchingPatterns); } 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 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); } } if (logger.isDebugEnabled()) { logger.debug("URI Template variables for request [" + urlPath + "] are " + uriTemplateVariables); } return buildPathExposingHandler(handler, bestPatternMatch, pathWithinMapping, uriTemplateVariables); } // No handler found... return null; }
通過一系列的對HTTP請求進行解析和匹配handler的過程,獲得了與請求對應的處理器。在返回handler中,已經完成了對HandlerExecutionChain進行封裝工做,爲HTTP請求響應作準備。
回到DispatcherServlet中,對HTTP的請求是在doService中,DispatcherServlet是HttpServlet的子類,和其餘Servlet同樣,經過doService來響應HTTP請求。doService直接調用的是doDispatch方法
主要看一下這個方法。
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);//獲取handler if (mappedHandler == null || mappedHandler.getHandler() == null) { noHandlerFound(processedRequest, response); return; } // Determine handler adapter for the current request.//獲取adapter HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler()); // Process last-modified header, if supported by the handler. String method = request.getMethod(); boolean isGet = "GET".equals(method); if (isGet || "HEAD".equals(method)) { long lastModified = ha.getLastModified(request, mappedHandler.getHandler()); if (logger.isDebugEnabled()) { logger.debug("Last-Modified value for [" + getRequestUri(request) + "] is: " + lastModified); } if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) { return; } } if (!mappedHandler.applyPreHandle(processedRequest, response)) { return; } // Actually invoke the handler.handler處理的結果封裝到mv中 mv = ha.handle(processedRequest, response, mappedHandler.getHandler()); if (asyncManager.isConcurrentHandlingStarted()) { return; } applyDefaultViewName(request, mv); mappedHandler.applyPostHandle(processedRequest, response, mv); } catch (Exception ex) { dispatchException = ex; } processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException); } catch (Exception ex) { triggerAfterCompletion(processedRequest, response, mappedHandler, ex); } catch (Error err) { triggerAfterCompletionWithError(processedRequest, response, mappedHandler, err); } finally { if (asyncManager.isConcurrentHandlingStarted()) { // Instead of postHandle and afterCompletion if (mappedHandler != null) { mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response); } } else { // Clean up any resources used by a multipart request. if (multipartRequestParsed) { cleanupMultipart(processedRequest); } } } }
看一下getHandlerAdapter方法
protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException { for (HandlerAdapter ha : this.handlerAdapters) { if (logger.isTraceEnabled()) { logger.trace("Testing handler adapter [" + ha + "]"); } if (ha.supports(handler)) {//判斷是否支持 return ha; } } throw new ServletException("No adapter for handler [" + handler + "]: The DispatcherServlet configuration needs to include a HandlerAdapter that supports this handler"); }
繼續看一下supports方法的實現,以SimpleControlerHandlerAdapter類爲例
public class SimpleControllerHandlerAdapter implements HandlerAdapter { @Override public boolean supports(Object handler) { return (handler instanceof Controller); } @Override public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { return ((Controller) handler).handleRequest(request, response); } @Override public long getLastModified(HttpServletRequest request, Object handler) { if (handler instanceof LastModified) { return ((LastModified) handler).getLastModified(request); } return -1L; } }
通過上面一系列的操做,獲得handler對象,handler調用handleRequest方法,返回ModelAndView對象,最後經過render方法進行渲染。
問題:handlerMapping是在何時初始化的?
在DispatcherServlet調用init->initStrategies方法中,進行初始化。
protected void initStrategies(ApplicationContext context) { initMultipartResolver(context); initLocaleResolver(context); initThemeResolver(context); //初始化handlerMapping initHandlerMappings(context); initHandlerAdapters(context); initHandlerExceptionResolvers(context); initRequestToViewNameTranslator(context); initViewResolvers(context); initFlashMapManager(context); }
最後一個請求的流程圖。