AbstractHandlerMapping implements the getHandler specified by the HandlerMapping interface
1. Provide getHandlerInternal template method to subclass implementation
2. If the Handler is not obtained, the default defaultHandler is used.
3. If handler is of string type, get the instance from context
4. Encapsulate the handler through getHandlerExecutionChain and add the interceptor
// AbstractHandlerMapping/*** Look up a handler for the given request, falling back to the default* handler if no specific one is found.* @param request current HTTP request* @return the corresponding handler instance, or the default handler* @see #getHandlerInternal*/public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {Object handler = getHandlerInternal(request);if (handler == null) {handler = getDefaultHandler();}if (handler == null) {return null;}// Bean name or resolved handler?if (handler instance of String) {String handlerName = (String) handler;handler = getApplicationContext().getBean(handlerName);}return getHandlerExecutionChain(handler, request);} // AbstractHandlerMapping/*** Build a HandlerExecutionChain for the given handler, including applicable interceptors.* <p>The default implementation simply builds a standard HandlerExecutionChain with* the given handler, the handler mapping's common interceptors, and any {@link MappedInterceptor}s* matching to the current request URL. Subclasses may* override this in order to extend/rearrange the list of interceptors.* <p><b>NOTE:</b> The passed-in handler object may be a raw handler or a pre-built* HandlerExecutionChain. This method should handle those two cases explicitly,* either building a new HandlerExecutionChain or extending the existing chain.* <p>For simply adding an interceptor, consider calling {@code super.getHandlerExecutionChain}* and invoking {@link HandlerExecutionChain#addInterceptor} on the returned chain object.* @param handler the resolved handler instance (never {@code null})* @param request current HTTP request* @return the HandlerExecutionChain (never {@code null})* @see #getAdaptedInterceptors()*/protected HandlerExecutionChain getHandlerExecutionChain(Object handler, HttpServletRequest request) {HandlerExecutionChain chain =(handler instanceof HandlerExecutionChain) handler : new HandlerExecutionChain(handler); chain.addInterceptors(getAdaptedInterceptors());String lookupPath = urlPathHelper.getLookupPathForRequest(request);for (MappedInterceptor mappedInterceptor : mappedInterceptors) {if (mappedInterceptor.matches(lookupPath, pathMatcher)) {chain.addInterceptor(mappedInterceptor.getInterceptor());}}return chain;} Next, take a look at the getHandlerInternal implemented by AbstractUrlHandlerMapping
// AbstractUrlHandlerMapping/*** Look up a handler for the URL path of the given request.* @param request current HTTP request* @return the handler instance, or {@code null} if none found*/@Overrideprotected Object getHandlerInternal(HttpServletRequest request) throws Exception {// Get urlString lookupPath = getUrlPathHelper().getLookupPathForRequest(request);// Find handlerObject handler = lookupHandler(lookupPath, request);if (handler == null) {// If there is no match for the handler, you need to find the default one, and you need to cache PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE to request// 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 instance of String) {String handlerName = (String) rawHandler;rawHandler = getApplicationContext().getBean(handlerName);}// The reserved verification handler template method does not use validateHandler(rawHandler, request);// Add the expose attribute to the interceptor handler of the request handler = buildPathExposedHandler(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;} // AbstractUrlHandlerMapping/*** Look up a handler instance for the given URL path.* <p>Supports direct matches, eg a registered "/test" matches "/test",* and various Ant-style pattern matches, eg a registered "/t*" matches* both "/test" and "/team". For details, see the AntPathMatcher class.* <p>Looks for the most exact pattern, where most exact is defined as* the longest path pattern.* @param urlPath URL the bean is mapped to* @param request current HTTP request (to expose the path within the mapping to)* @return the associated handler instance, or {@code null} if not found* @see #exposePathWithinMapping* @see org.springframework.util.AntPathMatcher*/protected Object lookupHandler(String urlPath, HttpServletRequest request) throws Exception {// Direct match? Directly search handlerObject 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 buildPathExposedHandler(handler, urlPath, urlPath, null);}// Pattern match? Matching through expressions is implemented through AntPathMatcher. The specific analysis is given below 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);}// The lowest order number has the highest priority bestPatternMatch = matchingPatterns.get();}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 themMap<String, String> uriTemplateVariables = new LinkedHashMap<String, String>(); for (String matchingPattern : matchingPatterns) {if (patternComparator.compare(bestPatternMatch, matchingPattern) == ) {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 buildPathExposedHandler(handler, bestPatternMatch, pathWithinMapping, uriTemplateVariables);}// No handler found...return null;} Designed to verify Handlers, nothing is done, including subclasses.
/*** Validate the given handler against the current request.* <p>The default implementation is empty. Can be overridden in subclasses,* for example to enforce specific preconditions expressed in URL mappings.* @param handler the handler object to validate* @param request current HTTP request* @throws Exception if validation failed*/protected void validateHandler(Object handler, HttpServletRequest request) throws Exception {} Encapsulate handler as HandlerExecutionChain, and add PathExpositingHandlerInterceptor and UriTemplateVariablesHandlerInterceptor interceptor.
/*** Build a handler object for the given raw handler, exposing the actual* handler, the {@link #PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE}, as well as* the {@link #URI_TEMPLATE_VARIABLES_ATTRIBUTE} before executing the handler.* <p>The default implementation builds a {@link HandlerExecutionChain}* with a special interceptor that exposes the path attribute and uri template variables* @param rawHandler the raw handler to expose* @param pathWithinMapping the path to expose before executing the handler* @param uriTemplateVariables the URI template variables, can be {@code null} if no variables found* @return the final handler object*/protected Object buildPathExposedHandler(Object rawHandler, String bestMatchingPattern,String pathWithinMapping, Map<String, String> uriTemplateVariables) {HandlerExecutionChain chain = new HandlerExecutionChain(rawHandler); chain.addInterceptor(new PathExposedHandlerInterceptor(bestMatchingPattern, pathWithinMapping));if (!CollectionUtils.isEmpty(uriTemplateVariables)) {chain.addInterceptor(new UriTemplateVariablesHandlerInterceptor(uriTemplateVariables));} return chain;}The above content is the relevant knowledge of the SpringMVC source code interpretation of HandlerMapping - AbstractUrlHandlerMapping series request distribution introduced to you. I hope it will be helpful to everyone!