下面是网上的一张流程图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
完