SpringMVC源碼解讀,springmvc源碼
AbstractHandlerMapping實現HandlerMapping介面定的getHandler
1. 提供getHandlerInternal模板方法給子類實現
2. 如果沒有擷取Handler,則使用預設的defaultHandler
3. 如果handler是string類型,從context擷取執行個體
4. 通過getHandlerExecutionChain封裝handler,添加interceptor
// AbstractHandlerMapping
1 /** 2 * Look up a handler for the given request, falling back to the default 3 * handler if no specific one is found. 4 * @param request current HTTP request 5 * @return the corresponding handler instance, or the default handler 6 * @see #getHandlerInternal 7 */ 8 public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception { 9 Object handler = getHandlerInternal(request);10 if (handler == null) {11 handler = getDefaultHandler();12 }13 if (handler == null) {14 return null;15 }16 // Bean name or resolved handler?17 if (handler instanceof String) {18 String handlerName = (String) handler;19 handler = getApplicationContext().getBean(handlerName);20 }21 return getHandlerExecutionChain(handler, request);22 }
// AbstractHandlerMapping
1 /** 2 * Build a HandlerExecutionChain for the given handler, including applicable interceptors. 3 * <p>The default implementation simply builds a standard HandlerExecutionChain with 4 * the given handler, the handler mapping's common interceptors, and any {@link MappedInterceptor}s 5 * matching to the current request URL. Subclasses may 6 * override this in order to extend/rearrange the list of interceptors. 7 * <p><b>NOTE:</b> The passed-in handler object may be a raw handler or a pre-built 8 * HandlerExecutionChain. This method should handle those two cases explicitly, 9 * either building a new HandlerExecutionChain or extending the existing chain.10 * <p>For simply adding an interceptor, consider calling {@code super.getHandlerExecutionChain}11 * and invoking {@link HandlerExecutionChain#addInterceptor} on the returned chain object.12 * @param handler the resolved handler instance (never {@code null})13 * @param request current HTTP request14 * @return the HandlerExecutionChain (never {@code null})15 * @see #getAdaptedInterceptors()16 */17 protected HandlerExecutionChain getHandlerExecutionChain(Object handler, HttpServletRequest request) {18 HandlerExecutionChain chain =19 (handler instanceof HandlerExecutionChain) ?20 (HandlerExecutionChain) handler : new HandlerExecutionChain(handler);21 22 chain.addInterceptors(getAdaptedInterceptors());23 24 String lookupPath = urlPathHelper.getLookupPathForRequest(request);25 for (MappedInterceptor mappedInterceptor : mappedInterceptors) {26 if (mappedInterceptor.matches(lookupPath, pathMatcher)) {27 chain.addInterceptor(mappedInterceptor.getInterceptor());28 }29 }30 31 return chain;32 }
接下來看看AbstractUrlHandlerMapping實現的getHandlerInternal
// AbstractUrlHandlerMapping
1 /** 2 * Look up a handler for the URL path of the given request. 3 * @param request current HTTP request 4 * @return the handler instance, or {@code null} if none found 5 */ 6 @Override 7 protected Object getHandlerInternal(HttpServletRequest request) throws Exception { 8 // 根據request擷取url 9 String lookupPath = getUrlPathHelper().getLookupPathForRequest(request);10 // 根據url尋找handler11 Object handler = lookupHandler(lookupPath, request);12 if (handler == null) {13 // 如果沒有匹配到handler需要尋找預設的,下面需要將PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE緩衝到request14 // We need to care for the default handler directly, since we need to15 // expose the PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE for it as well.16 Object rawHandler = null;17 if ("/".equals(lookupPath)) {18 rawHandler = getRootHandler();19 }20 if (rawHandler == null) {21 rawHandler = getDefaultHandler();22 }23 if (rawHandler != null) {24 // Bean name or resolved handler?25 if (rawHandler instanceof String) {26 String handlerName = (String) rawHandler;27 rawHandler = getApplicationContext().getBean(handlerName);28 }29 // 預留的校正handler模板方法,沒有使用30 validateHandler(rawHandler, request);31 // 添加expose屬性到request的攔截器32 handler = buildPathExposingHandler(rawHandler, lookupPath, lookupPath, null);33 }34 }35 if (handler != null && logger.isDebugEnabled()) {36 logger.debug("Mapping [" + lookupPath + "] to " + handler);37 }38 else if (handler == null && logger.isTraceEnabled()) {39 logger.trace("No handler mapping found for [" + lookupPath + "]");40 }41 return handler;42 }
// AbstractUrlHandlerMapping
1 /** 2 * Look up a handler instance for the given URL path. 3 * <p>Supports direct matches, e.g. a registered "/test" matches "/test", 4 * and various Ant-style pattern matches, e.g. a registered "/t*" matches 5 * both "/test" and "/team". For details, see the AntPathMatcher class. 6 * <p>Looks for the most exact pattern, where most exact is defined as 7 * the longest path pattern. 8 * @param urlPath URL the bean is mapped to 9 * @param request current HTTP request (to expose the path within the mapping to)10 * @return the associated handler instance, or {@code null} if not found11 * @see #exposePathWithinMapping12 * @see org.springframework.util.AntPathMatcher13 */14 protected Object lookupHandler(String urlPath, HttpServletRequest request) throws Exception {15 // Direct match? 直接根據url進行尋找handler16 Object handler = this.handlerMap.get(urlPath);17 if (handler != null) {18 // Bean name or resolved handler?19 if (handler instanceof String) {20 String handlerName = (String) handler;21 handler = getApplicationContext().getBean(handlerName);22 }23 validateHandler(handler, request);24 return buildPathExposingHandler(handler, urlPath, urlPath, null);25 }26 // Pattern match? 通過運算式進行匹配具體通過AntPathMatcher實現,具體後面分析27 List<String> matchingPatterns = new ArrayList<String>();28 for (String registeredPattern : this.handlerMap.keySet()) {29 if (getPathMatcher().match(registeredPattern, urlPath)) {30 matchingPatterns.add(registeredPattern);31 }32 }33 String bestPatternMatch = null;34 Comparator<String> patternComparator = getPathMatcher().getPatternComparator(urlPath);35 if (!matchingPatterns.isEmpty()) {36 Collections.sort(matchingPatterns, patternComparator);37 if (logger.isDebugEnabled()) {38 logger.debug("Matching patterns for request [" + urlPath + "] are " + matchingPatterns);39 }40 // order序號最小的優先順序最高41 bestPatternMatch = matchingPatterns.get(0);42 }43 if (bestPatternMatch != null) {44 handler = this.handlerMap.get(bestPatternMatch);45 // Bean name or resolved handler?46 if (handler instanceof String) {47 String handlerName = (String) handler;48 handler = getApplicationContext().getBean(handlerName);49 }50 validateHandler(handler, request);51 String pathWithinMapping = getPathMatcher().extractPathWithinPattern(bestPatternMatch, urlPath);52 53 // There might be multiple 'best patterns', let's make sure we have the correct URI template variables54 // for all of them55 Map<String, String> uriTemplateVariables = new LinkedHashMap<String, String>();56 for (String matchingPattern : matchingPatterns) {57 if (patternComparator.compare(bestPatternMatch, matchingPattern) == 0) {58 Map<String, String> vars = getPathMatcher().extractUriTemplateVariables(matchingPattern, urlPath);59 Map<String, String> decodedVars = getUrlPathHelper().decodePathVariables(request, vars);60 uriTemplateVariables.putAll(decodedVars);61 }62 }63 if (logger.isDebugEnabled()) {64 logger.debug("URI Template variables for request [" + urlPath + "] are " + uriTemplateVariables);65 }66 return buildPathExposingHandler(handler, bestPatternMatch, pathWithinMapping, uriTemplateVariables);67 }68 // No handler found...69 return null;70 }
設計用於校正Handler,實際什麼都沒做,包括子類.
1 /** 2 * Validate the given handler against the current request. 3 * <p>The default implementation is empty. Can be overridden in subclasses, 4 * for example to enforce specific preconditions expressed in URL mappings. 5 * @param handler the handler object to validate 6 * @param request current HTTP request 7 * @throws Exception if validation failed 8 */ 9 protected void validateHandler(Object handler, HttpServletRequest request) throws Exception {10 }
封裝handler為HandlerExecutionChain,並添加PathExposingHandlerInterceptor和UriTemplateVariablesHandlerInterceptor攔截器.
1 /** 2 * Build a handler object for the given raw handler, exposing the actual 3 * handler, the {@link #PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE}, as well as 4 * the {@link #URI_TEMPLATE_VARIABLES_ATTRIBUTE} before executing the handler. 5 * <p>The default implementation builds a {@link HandlerExecutionChain} 6 * with a special interceptor that exposes the path attribute and uri template variables 7 * @param rawHandler the raw handler to expose 8 * @param pathWithinMapping the path to expose before executing the handler 9 * @param uriTemplateVariables the URI template variables, can be {@code null} if no variables found10 * @return the final handler object11 */12 protected Object buildPathExposingHandler(Object rawHandler, String bestMatchingPattern,13 String pathWithinMapping, Map<String, String> uriTemplateVariables) {14 15 HandlerExecutionChain chain = new HandlerExecutionChain(rawHandler);16 chain.addInterceptor(new PathExposingHandlerInterceptor(bestMatchingPattern, pathWithinMapping));17 if (!CollectionUtils.isEmpty(uriTemplateVariables)) {18 chain.addInterceptor(new UriTemplateVariablesHandlerInterceptor(uriTemplateVariables));19 }20 return chain;21 }