SpringMVC源码解读 - HandlerMapping - AbstractUrlHandlerMapping系列request分发
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 request 14 * @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查找handler 11 Object handler = lookupHandler(lookupPath, request); 12 if (handler == null) { 13 // 如果没有匹配到handler需要查找默认的,下面需要将PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE缓存到request 14 // We need to care for the default handler directly, since we need to 15 // 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 found 11 * @see #exposePathWithinMapping 12 * @see org.springframework.util.AntPathMatcher 13 */ 14 protected Object lookupHandler(String urlPath, HttpServletRequest request) throws Exception { 15 // Direct match? 直接根据url进行查找handler 16 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 variables 54 // for all of them 55 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 found 10 * @return the final handler object 11 */ 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 }