下面是網上的一張流程圖session
全部請求通過Dispatcher Servlet再通過HandlerMapping尋找指定的Controller
咱們看看DispatcherServlet的部分源碼app
... private List<HandlerMapping> handlerMappings; ... protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception { Iterator var2 = this.handlerMappings.iterator(); HandlerExecutionChain handler; do { if(!var2.hasNext()) { return null; } HandlerMapping hm = (HandlerMapping)var2.next(); if(this.logger.isTraceEnabled()) { this.logger.trace("Testing handler map [" + hm + "] in DispatcherServlet with name '" + this.getServletName() + "'"); } handler = hm.getHandler(request); } while(handler == null); return handler; }
關鍵就是handler = hm.getHandler(request);這句根據request取得對應的Handler。咱們接下來再看看HandlerMapping裏是如何實現request的註冊與查找的。ide
先看一張繼承圖this
1.咱們先從頂層的HandlerMapping看起
如下是它的源碼:url
public interface HandlerMapping { String PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE = HandlerMapping.class.getName() + ".pathWithinHandlerMapping" ; String BEST_MATCHING_PATTERN_ATTRIBUTE = HandlerMapping.class.getName() + ".bestMatchingPattern"; String INTROSPECT_TYPE_LEVEL_MAPPING = HandlerMapping.class.getName() + ".introspectTypeLevelMapping" ; String URI_TEMPLATE_VARIABLES_ATTRIBUTE = HandlerMapping.class.getName() + ".uriTemplateVariables"; String MATRIX_VARIABLES_ATTRIBUTE = HandlerMapping.class.getName() + ".matrixVariables"; String PRODUCIBLE_MEDIA_TYPES_ATTRIBUTE = HandlerMapping.class.getName() + ".producibleMediaTypes"; /** * Return a handler and any interceptors for this request. The choice may be made * on request URL, session state, or any factor the implementing class chooses. * <p>The returned HandlerExecutionChain contains a handler Object, rather than * even a tag interface, so that handlers are not constrained in any way. * For example, a HandlerAdapter could be written to allow another framework's * handler objects to be used. * <p>Returns <code> null</code> if no match was found. This is not an error. * The DispatcherServlet will query all registered HandlerMapping beans to find * a match, and only decide there is an error if none can find a handler. * @param request current HTTP request * @return a HandlerExecutionChain instance containing handler object and * any interceptors, or <code>null</code> if no mapping found * @throws Exception if there is an internal error */ HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception; }
着重看註釋中的這兩段話spa
咱們再看看具體的實現類(AbstractUrlHandlerMapping)裏是如何註冊request與獲取handler的code
... ... private final Map<String, Object> handlerMap = new LinkedHashMap(); ... ... 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; if(!this.lazyInitHandlers && handler instanceof String) { String handlerName = (String)handler; if(this.getApplicationContext().isSingleton(handlerName)) { resolvedHandler = this.getApplicationContext().getBean(handlerName); } } Object mappedHandler = this.handlerMap.get(urlPath); if(mappedHandler != null) { if(mappedHandler != resolvedHandler) { throw new IllegalStateException("Cannot map " + this.getHandlerDescription(handler) + " to URL path [" + urlPath + "]: There is already " + this.getHandlerDescription(mappedHandler) + " mapped."); } } else if(urlPath.equals("/")) { if(this.logger.isInfoEnabled()) { this.logger.info("Root mapping to " + this.getHandlerDescription(handler)); } this.setRootHandler(resolvedHandler); } else if(urlPath.equals("/*")) { if(this.logger.isInfoEnabled()) { this.logger.info("Default mapping to " + this.getHandlerDescription(handler)); } this.setDefaultHandler(resolvedHandler); } else { this.handlerMap.put(urlPath, resolvedHandler); if(this.logger.isInfoEnabled()) { this.logger.info("Mapped URL path [" + urlPath + "] onto " + this.getHandlerDescription(handler)); } } } ... ... protected Object getHandlerInternal(HttpServletRequest request) throws Exception { String lookupPath = this.getUrlPathHelper().getLookupPathForRequest(request); Object handler = this.lookupHandler(lookupPath, request); ... ... protected Object lookupHandler(String urlPath, HttpServletRequest request) throws Exception { Object handler = this.handlerMap.get(urlPath); if(handler != null) { if(handler instanceof String) { String handlerName = (String)handler; handler = this.getApplicationContext().getBean(handlerName); } ... ...
註冊的關鍵代碼是以下兩行繼承
從上下問中獲取相應的Bean,而後以url爲key,handler爲value添加到Map中。ip
獲取handler也很簡單,直接再Map里根據查找。ci
完