springboot源码分析:DispatchServlet的工作原理

Scroll Down

DispatcherServlet的工作原理

DispatcherServlet的工作原理分为两部分:
(1)、DispatcherServlet的初始化。
(2)、DispatcherServlet处理请求。
PS:第一部分在之前的SpringMVC初始化过程中已经介绍了,并且在SpringMVC相关组件中详细说明了。此处不再详细介绍。本文主要介绍DispatcherServlet处理请求。

1、DispatcherServlet处理请求原理

DispatcherServlet的类结构图如下:
image.png

收到一个用户请求的起始位置是在HttpServlet的service方法中。

@Override
public void service(ServletRequest req, ServletResponse res)
        throws ServletException, IOException {

    HttpServletRequest  request;
    HttpServletResponse response;

    try {
        request = (HttpServletRequest) req;
        response = (HttpServletResponse) res;
    } catch (ClassCastException e) {
        throw new ServletException(lStrings.getString("http.non_http"));
    }
    service(request, response);
}

最后会调用DispatcherServlet的doDispatch方法

protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
	HttpServletRequest processedRequest = request;
	HandlerExecutionChain mappedHandler = null;
	boolean multipartRequestParsed = false;

	WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);

	try {
		ModelAndView mv = null;
		Exception dispatchException = null;

		try {
			processedRequest = checkMultipart(request);
			multipartRequestParsed = (processedRequest != request);

			// Determine handler for the current request.
			mappedHandler = getHandler(processedRequest);
			if (mappedHandler == null) {
					noHandlerFound(processedRequest, response);
				return;
			}

			// Determine handler adapter for the current request.
			HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());

			// Process last-modified header, if supported by the handler.
			String method = request.getMethod();
			boolean isGet = "GET".equals(method);
			if (isGet || "HEAD".equals(method)) {
				long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
				if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
					return;
				}
			}

			if (!mappedHandler.applyPreHandle(processedRequest, response)) {
				return;
			}

			// Actually invoke the handler.
			mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

			if (asyncManager.isConcurrentHandlingStarted()) {
				return;
			}

			applyDefaultViewName(processedRequest, mv);
			mappedHandler.applyPostHandle(processedRequest, response, mv);
		}
		catch (Exception ex) {
			dispatchException = ex;
		}
		catch (Throwable err) {
			// As of 4.3, we're processing Errors thrown from handler methods as well,
			// making them available for @ExceptionHandler methods and other scenarios.
			dispatchException = new NestedServletException("Handler dispatch failed", err);
		}
		processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
	}
	catch (Exception ex) {
		triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
	}
	catch (Throwable err) {
		triggerAfterCompletion(processedRequest, response, mappedHandler,
					new NestedServletException("Handler processing failed", err));
	}
	finally {
		if (asyncManager.isConcurrentHandlingStarted()) {
			// Instead of postHandle and afterCompletion
			if (mappedHandler != null) {
				mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
			}
		}
		else {
			// Clean up any resources used by a multipart request.
			if (multipartRequestParsed) {
				cleanupMultipart(processedRequest);
			}
		}
	}
}
(1)、处理多块请求

首先会判断这个请求是否是多块请求(比如上传文件),如果是,那么会将request封装成MultipartHttpServletRequest,如果不是则继续向下处理。(具体多块请求原理在组件介绍的时候已经讲过)

(2)、获取处理器

接下来会尝试获取HandlerExecutionChain。在讲述DispatcherServlet组件的时候对于流程已经大概说明了,这里详细再介绍下里面的原理及细节。
还是以RequestMappingHandlerMapping为例。RequestMappingHandlerMapping的结构图如下:
image.png

HandlerMapping的运行原理分为两部分:
第一部分是初始化操作,在初始化阶段HandlerMapping会加载所有被@Controller和@RequestMapping注解标记的类和方法供执行阶段使用。
第二部分是获取Handler的操作,在运行阶段DispatcherServlet会通过HandlerMapping获取HandlerExecutionChain。
初始化操作流程分析:
首先RequestMappingHandlerMapping由于该类实现了InitializingBean,那么在容器中创建这个类的实例的时候会调用afterPropertiesSet()执行初始化操作。
RequestMappingHandlerMapping中的afterPropertiesSet方法如下:

@Override
public void afterPropertiesSet() {
	this.config = new RequestMappingInfo.BuilderConfiguration();
	this.config.setUrlPathHelper(getUrlPathHelper());
	this.config.setPathMatcher(getPathMatcher());
	this.config.setSuffixPatternMatch(this.useSuffixPatternMatch);
	this.config.setTrailingSlashMatch(this.useTrailingSlashMatch);
	this.config.setRegisteredSuffixPatternMatch(this.useRegisteredSuffixPatternMatch);
	this.config.setContentNegotiationManager(getContentNegotiationManager());

	super.afterPropertiesSet();
}

具体的实现操作则是在AbstractHandlerMethodMapping的initHandlerMethods方法中。

protected void initHandlerMethods() {
	for (String beanName : getCandidateBeanNames()) {
		if (!beanName.startsWith(SCOPED_TARGET_NAME_PREFIX)) {
			processCandidateBean(beanName);
		}
	}
	handlerMethodsInitialized(getHandlerMethods());
}

方法中首先会获取容器中所有被注册的beanName,然后对所有的bean执行筛选操作。具体的方法是在processCandidateBean中执行的。PS:SCOPED_TARGET_NAME_PREFIX官方注释中给出的解释是避免spring-aop硬依赖,目前还不理解为什么。

protected void processCandidateBean(String beanName) {
	Class<?> beanType = null;
	try {
		beanType = obtainApplicationContext().getType(beanName);
	}
	catch (Throwable ex) {
		// An unresolvable bean type, probably from a lazy bean - let's ignore it.
		if (logger.isTraceEnabled()) {
			logger.trace("Could not resolve type for bean '" + beanName + "'", ex);
		}
	}
	if (beanType != null && isHandler(beanType)) {
		detectHandlerMethods(beanName);
	}
}

在processCandidateBean方法中,首先通过beanName来获取Class,接下来会判断这个Class是否是一个HandlerMapping。isHandler方法在AbstractHandlerMethodMapping是一个抽象方法,在具体的子类中会对其进行实现。在RequestMappingHandlerMapping的判断逻辑:

Override
protected boolean isHandler(Class<?> beanType) {
	return (AnnotatedElementUtils.hasAnnotation(beanType, Controller.class) ||
				AnnotatedElementUtils.hasAnnotation(beanType, RequestMapping.class));
}

会判断这个Class是否有Controller或者RequestMapping注解。
detectHandlerMethods是AbstractHandlerMethodMapping的一个模版方法,这个方法的核心内容是根据实现类的方法来获取指定条件的Method数组,然后将这些Method包装成HandlerMethod注册到MappingRegistry中。

protected void detectHandlerMethods(Object handler) {
	Class<?> handlerType = (handler instanceof String ?
				obtainApplicationContext().getType((String) handler) : handler.getClass());

	if (handlerType != null) {
		Class<?> userType = ClassUtils.getUserClass(handlerType);
		Map<Method, T> methods = MethodIntrospector.selectMethods(userType,
					(MethodIntrospector.MetadataLookup<T>) method -> {
					try {
						return getMappingForMethod(method, userType);
					}
					catch (Throwable ex) {
						throw new IllegalStateException("Invalid mapping on handler class [" +
									userType.getName() + "]: " + method, ex);
					}
				});
		if (logger.isTraceEnabled()) {
			logger.trace(formatMappings(userType, methods));
		}
		methods.forEach((method, mapping) -> {
			Method invocableMethod = AopUtils.selectInvocableMethod(method, userType);
			registerHandlerMethod(handler, invocableMethod, mapping);
		});
	}
}

首先如果此时的handler还是String的话还会从容器中获取Class,然后通过工具类MethodIntrospector的selectMethods方法根据指定的条件筛选出Method和元数据信息,具体的信息可以通过泛型指定。

public static <T> Map<Method, T> selectMethods(Class<?> targetType, final MetadataLookup<T> metadataLookup) {
	final Map<Method, T> methodMap = new LinkedHashMap<>();
	Set<Class<?>> handlerTypes = new LinkedHashSet<>();
	Class<?> specificHandlerType = null;

	if (!Proxy.isProxyClass(targetType)) {
		specificHandlerType = ClassUtils.getUserClass(targetType);
		handlerTypes.add(specificHandlerType);
	}
	handlerTypes.addAll(ClassUtils.getAllInterfacesForClassAsSet(targetType));

	for (Class<?> currentHandlerType : handlerTypes) {
		final Class<?> targetClass = (specificHandlerType != null ? specificHandlerType : currentHandlerType);

		ReflectionUtils.doWithMethods(currentHandlerType, method -> {
			Method specificMethod = ClassUtils.getMostSpecificMethod(method, targetClass);
			T result = metadataLookup.inspect(specificMethod);
			if (result != null) {
				Method bridgedMethod = BridgeMethodResolver.findBridgedMethod(specificMethod);
				if (bridgedMethod == specificMethod || metadataLookup.inspect(bridgedMethod) == null) {
					methodMap.put(specificMethod, result);
				}
			}
		}, ReflectionUtils.USER_DECLARED_METHODS);
	}

	return methodMap;
}

在selectMethods方法中核心处理逻辑是使用ReflectionUtils这个工具类的doWithMethods方法。
从网上查了些资料,这里详细讲下doWithMethods方法。
void doWithLocalMethods(Class<?> clazz, MethodCallback mc)
针对指定类型上的所有方法,依次调用MethodCallback回调;
首先来看看MethodCallback接口声明:

/**
 * Action to take on each method.
 */
@FunctionalInterface
public interface MethodCallback {

	/**
	 * Perform an operation using the given method.
	 * @param method the method to operate on
	 */
	void doWith(Method method) throws IllegalArgumentException, IllegalAccessException;
}

其实就是一个正常的回调接口;来看看doWithLocalMethods实现:

public static void doWithLocalMethods(Class<?> clazz, MethodCallback mc) {
	Method[] methods = getDeclaredMethods(clazz, false);
	for (Method method : methods) {
		try {
			mc.doWith(method);
		}
		catch (IllegalAccessException ex) {
			throw new IllegalStateException("Not allowed to access method '" + method.getName() + "': " + ex);
		}
	}
}

其实实现很简单,就是得到类上的所有方法,然后执行回调接口;这个方法在Spring针对bean的方法上的标签处理时大量使用,比如@Init,@Resource,@Autowire等标签的预处理;
该方法有一个增强版:
void doWithMethods(Class<?> clazz, MethodCallback mc, MethodFilter mf)
该版本提供了一个方法匹配(过滤器)MethodFilter;

/**
 * Callback optionally used to filter methods to be operated on by a method callback.
 */
@FunctionalInterface
public interface MethodFilter {

	/**
	 * Determine whether the given method matches.
	 * @param method the method to check
	 */
	boolean matches(Method method);
}

该接口就声明了一个匹配方法,用于匹配规则;

public static void doWithMethods(Class<?> clazz, MethodCallback mc, @Nullable MethodFilter mf) {
	// Keep backing up the inheritance hierarchy.
	Method[] methods = getDeclaredMethods(clazz, false);
	for (Method method : methods) {
		if (mf != null && !mf.matches(method)) {
			continue;
		}
		try {
			mc.doWith(method);
		}
		catch (IllegalAccessException ex) {
			throw new IllegalStateException("Not allowed to access method '" + method.getName() + "': " + ex);
		}
	}
	if (clazz.getSuperclass() != null && (mf != USER_DECLARED_METHODS || clazz.getSuperclass() != Object.class)) {
		doWithMethods(clazz.getSuperclass(), mc, mf);
	}
	else if (clazz.isInterface()) {
		for (Class<?> superIfc : clazz.getInterfaces()) {
			doWithMethods(superIfc, mc, mf);
		}
	}
}

该方法实现就很明确了,首先得到类上所有方法,针对每一个方法,调用MethodFilter实现匹配检查,如果匹配上,调用MethodCallback回调方法。该方法会递归向上查询所有父类和实现的接口上的所有方法并处理;
所以在MethodIntrospector中的回调如下:

ReflectionUtils.doWithMethods(currentHandlerType, method -> {
			Method specificMethod = ClassUtils.getMostSpecificMethod(method, targetClass);
			T result = metadataLookup.inspect(specificMethod);
			if (result != null) {
				Method bridgedMethod = BridgeMethodResolver.findBridgedMethod(specificMethod);
				if (bridgedMethod == specificMethod || metadataLookup.inspect(bridgedMethod) == null) {
					methodMap.put(specificMethod, result);
				}
			}
		}, ReflectionUtils.USER_DECLARED_METHODS);

同样在AbstractHandlerMethodMapping中注册的回调如下:

Map<Method, T> methods = MethodIntrospector.selectMethods(userType,
				(MethodIntrospector.MetadataLookup<T>) method -> {
					try {
						return getMappingForMethod(method, userType);
					}
					catch (Throwable ex) {
						throw new IllegalStateException("Invalid mapping on handler class [" +
									userType.getName() + "]: " + method, ex);
					}
				});

该方法中会通过模版模式来调用getMappingForMethod,getMappingForMethod方法每个具体的子类都会覆盖,在RequestMappingHandlerMapping中如下:

@Override
@Nullable
protected RequestMappingInfo getMappingForMethod(Method method, Class<?> handlerType) {
	RequestMappingInfo info = createRequestMappingInfo(method);
	if (info != null) {
		RequestMappingInfo typeInfo = createRequestMappingInfo(handlerType);
		if (typeInfo != null) {
			info = typeInfo.combine(info);
		}
		String prefix = getPathPrefix(handlerType);
		if (prefix != null) {
			info = RequestMappingInfo.paths(prefix).options(this.config).build().combine(info);
		}
	}
	return info;
}

@Nullable
private RequestMappingInfo createRequestMappingInfo(AnnotatedElement element) {
	RequestMapping requestMapping = AnnotatedElementUtils.findMergedAnnotation(element, RequestMapping.class);
	RequestCondition<?> condition = (element instanceof Class ?
				getCustomTypeCondition((Class<?>) element) : getCustomMethodCondition((Method) element));
	return (requestMapping != null ? createRequestMappingInfo(requestMapping, condition) : null);
}

protected RequestMappingInfo createRequestMappingInfo(
			RequestMapping requestMapping, @Nullable RequestCondition<?> customCondition) {

	RequestMappingInfo.Builder builder = RequestMappingInfo
			.paths(resolveEmbeddedValuesInPatterns(requestMapping.path()))
			.methods(requestMapping.method())
			.params(requestMapping.params())
			.headers(requestMapping.headers())
			.consumes(requestMapping.consumes())
			.produces(requestMapping.produces())
			.mappingName(requestMapping.name());
	if (customCondition != null) {
		builder.customCondition(customCondition);
	}
	return builder.options(this.config).build();
}

最终封装成元数据RequestMappingInfo存入methods中。
接下来会将生成的methods的数据通过MappingRegistry注册到 Map<T, MappingRegistration> registry 供后续使用。

public void register(T mapping, Object handler, Method method) {
	// Assert that the handler method is not a suspending one.
	if (KotlinDetector.isKotlinType(method.getDeclaringClass()) && KotlinDelegate.isSuspend(method)) {
		throw new IllegalStateException("Unsupported suspending handler method detected: " + method);
	}
	this.readWriteLock.writeLock().lock();
	try {
		HandlerMethod handlerMethod = createHandlerMethod(handler, method);
		validateMethodMapping(handlerMethod, mapping);
		this.mappingLookup.put(mapping, handlerMethod);

		List<String> directUrls = getDirectUrls(mapping);
		for (String url : directUrls) {
			this.urlLookup.add(url, mapping);
		}

		String name = null;
		if (getNamingStrategy() != null) {
			name = getNamingStrategy().getName(handlerMethod, mapping);
			addMappingName(name, handlerMethod);
		}

		CorsConfiguration corsConfig = initCorsConfiguration(handler, method, mapping);
		if (corsConfig != null) {
			this.corsLookup.put(handlerMethod, corsConfig);
		}

		this.registry.put(mapping, new MappingRegistration<>(mapping, handlerMethod, directUrls, name));
	}
	finally {
		this.readWriteLock.writeLock().unlock();
	}
}

至此,DispatcherServlet在初始化阶段执行的操作就介绍完成。

获取Handler操作流程分析:
入口如下:

@Nullable
protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
	if (this.handlerMappings != null) {
		for (HandlerMapping mapping : this.handlerMappings) {
			HandlerExecutionChain handler = mapping.getHandler(request);
			if (handler != null) {
				return handler;
			}
		}
	}
	return null;
}

这里获取HandlerExecutionChain还是以RequestMappingHandlerMapping为例。getHandler的主体方法还是在AbstractHandlerMapping中进行的。

@Override
@Nullable
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 instanceof String) {
		String handlerName = (String) handler;
		handler = obtainApplicationContext().getBean(handlerName);
	}

	HandlerExecutionChain executionChain = getHandlerExecutionChain(handler, request);

	if (logger.isTraceEnabled()) {
		logger.trace("Mapped to " + handler);
	}
	else if (logger.isDebugEnabled() && !request.getDispatcherType().equals(DispatcherType.ASYNC)) {
		logger.debug("Mapped to " + executionChain.getHandler());
	}

	if (hasCorsConfigurationSource(handler) || CorsUtils.isPreFlightRequest(request)) {
		CorsConfiguration config = (this.corsConfigurationSource != null ? this.corsConfigurationSource.getCorsConfiguration(request) : null);
		CorsConfiguration handlerConfig = getCorsConfiguration(handler, request);
		config = (config != null ? config.combine(handlerConfig) : handlerConfig);
		executionChain = getCorsHandlerExecutionChain(request, executionChain, config);
	}

	return executionChain;
}

核心的获取getHandlerInternal的方法则是在AbstractHandlerMapping实现的,后来又调用了AbstractHandlerMapping的getHandlerInternal方法。

/**
 * Look up a handler method for the given request.
 */
@Override
protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {
      // 首先从request中获取patch
	String lookupPath = getUrlPathHelper().getLookupPathForRequest(request);
   	// 将patch属性设置到request的attribute中
	request.setAttribute(LOOKUP_PATH, lookupPath);
	// 加锁
	this.mappingRegistry.acquireReadLock();
	try {
		// 获取HandlerMethod
		HandlerMethod handlerMethod = lookupHandlerMethod(lookupPath, request);
		// 如果提供的beanName是String,那么会获取该对象。
		return (handlerMethod != null ? handlerMethod.createWithResolvedBean() : null);
	}
	finally {
		//释放锁
		this.mappingRegistry.releaseReadLock();
	}
}

通过lookupHandlerMethod获取HandlerMethod

@Nullable
protected HandlerMethod lookupHandlerMethod(String lookupPath, HttpServletRequest request) throws Exception {
	// 匹配结果存放到这里
	List<Match> matches = new ArrayList<>();
	// 通过path直接获取匹配信息
	List<T> directPathMatches = this.mappingRegistry.getMappingsByUrl(lookupPath);
	if (directPathMatches != null) {
		// 将匹配到的结果封装成Match,Match定义了匹配信息和HandlerMethod
		/**
		 * Match的结构如下:
		 * private final T mapping;
		 * private final HandlerMethod handlerMethod;
		 */
		addMatchingMappings(directPathMatches, matches, request);
	}
	if (matches.isEmpty()) {
		// No choice but to go through all mappings...
		// 如果没有任务匹配的,那么会将所有的Mapping信息放到Match信息。		
 addMatchingMappings(this.mappingRegistry.getMappings().keySet(), matches, request);
	}

	if (!matches.isEmpty()) {
		// 这里的比较类是在RequestMappingInfo中的compareTo方法。
		Comparator<Match> comparator = new MatchComparator(getMappingComparator(request));
		matches.sort(comparator);
		// 获取最佳的匹配结果
		Match bestMatch = matches.get(0);
		if (matches.size() > 1) {
			if (logger.isTraceEnabled()) {
				logger.trace(matches.size() + " matching mappings: " + matches);
			}
			if (CorsUtils.isPreFlightRequest(request)) {
				return PREFLIGHT_AMBIGUOUS_MATCH;
			}
			Match secondBestMatch = matches.get(1);
			// 获取列表中第二个Match,如果两个比较之后相等,那么就抛出异常。
			if (comparator.compare(bestMatch, secondBestMatch) == 0) {
				Method m1 = bestMatch.handlerMethod.getMethod();
				Method m2 = secondBestMatch.handlerMethod.getMethod();
				String uri = request.getRequestURI();
				throw new IllegalStateException(
							"Ambiguous handler methods mapped for '" + uri + "': {" + m1 + ", " + m2 + "}");
			}
		}
		request.setAttribute(BEST_MATCHING_HANDLER_ATTRIBUTE, bestMatch.handlerMethod);
		handleMatch(bestMatch.mapping, lookupPath, request);
		return bestMatch.handlerMethod;
	}
	else {
		return handleNoMatch(this.mappingRegistry.getMappings().keySet(), lookupPath, request);
	}
}

获取Mapping信息是从addMatchingMappings的getMatchingMapping方法获取的,这个方法在AbstractHandlerMethodMapping中是抽象的,具体的实现是在子类RequestMappingInfoHandlerMapping中。

private void addMatchingMappings(Collection<T> mappings, List<Match> matches, HttpServletRequest request) {
	for (T mapping : mappings) {
		T match = getMatchingMapping(mapping, request);
		if (match != null) {
			matches.add(new Match(match, this.mappingRegistry.getMappings().get(mapping)));
		}
	}
}

@Override
protected RequestMappingInfo getMatchingMapping(RequestMappingInfo info, HttpServletRequest request) {
	// 使用RequestMappingInfo的getMatchingCondition方法来判断是否匹配。如果匹配成功就返回一个RequestMappingInfo,匹配失败就返回null。
	return info.getMatchingCondition(request);
}

RequestMappingInfo中的getMatchingCondition方法如下:

@Override
@Nullable
public RequestMappingInfo getMatchingCondition(HttpServletRequest request) {
	// 判断请求方法是否匹配,如果方法都不匹配则返回。
	RequestMethodsRequestCondition methods = this.methodsCondition.getMatchingCondition(request);
	if (methods == null) {
		return null;
	}
	// 请求参数匹配,params 元素可以进一步缩小请求映射的定位范围。使用 params 元素,可以让多个处理方法处理到同一个URL 的请求, 而这些请求的参数是不一样的。 
	ParamsRequestCondition params = this.paramsCondition.getMatchingCondition(request);
	if (params == null) {
		return null;
	}
	//  通过header元素来根据请求中的消息头内容缩小请求映射的范围。
	HeadersRequestCondition headers = this.headersCondition.(request);
	if (headers == null) {
		return null;
	}
	// produces 和 consumes 这两个元素来缩小请求映射类型的范围
	ConsumesRequestCondition consumes = this.consumesCondition.getMatchingCondition(request);
	if (consumes == null) {
		return null;
	}
	ProducesRequestCondition produces = this.producesCondition.getMatchingCondition(request);
	if (produces == null) {
		return null;
	}
	// 对应RequestMapping中的path来缩小请求映射的范围
	PatternsRequestCondition patterns = this.patternsCondition.getMatchingCondition(request);
	if (patterns == null) {
		return null;
	}
	RequestConditionHolder custom = this.customConditionHolder.getMatchingCondition(request);
	if (custom == null) {
		return null;
	}

	return new RequestMappingInfo(this.name, patterns,
				methods, params, headers, consumes, produces, custom.getCondition());
}

匹配好RequestMapping之后,会从已经注册的Map<T, HandlerMethod> mappingLookup中根据RequestMappingInfo取出HandlerMethod。并封装成Match后存储起来。这里对于各个Condition的getMatchingCondition缺少了详细的分析。需要补上。
接下来就是根据匹配到的结果进行排序。排序List的是MatchComparator类,这个类通过装饰模式,来实现比较的。代码如下:

private class MatchComparator implements Comparator<Match> {

	private final Comparator<T> comparator;

	public MatchComparator(Comparator<T> comparator) {
		this.comparator = comparator;
	}

	@Override
	public int compare(Match match1, Match match2) {
		return this.comparator.compare(match1.mapping, match2.mapping);
	}
}

内部实际上是依赖于构造器中传入的comparator来实现的。
排序的方法会调用

@Override
public int compareTo(RequestMappingInfo other, HttpServletRequest request) {
	int result;
	// Automatic vs explicit HTTP HEAD mapping
	if (HttpMethod.HEAD.matches(request.getMethod())) {
		result = this.methodsCondition.compareTo(other.getMethodsCondition(), request);
		if (result != 0) {
			return result;
		}
	}
	// 通过URL比较。
	result = this.patternsCondition.compareTo(other.getPatternsCondition(), request);
	if (result != 0) {
		return result;
	}
	// 通过param参数比较。
	result = this.paramsCondition.compareTo(other.getParamsCondition(), request);
	if (result != 0) {
		return result;
	}
	// 通过header比较。
	result = this.headersCondition.compareTo(other.getHeadersCondition(), request);
	if (result != 0) {
		return result;
	}
	// 通过consumers和produces比较。
	result = this.consumesCondition.compareTo(other.getConsumesCondition(), request);
	if (result != 0) {
		return result;
	}
	result = this.producesCondition.compareTo(other.getProducesCondition(), request);
	if (result != 0) {
		return result;
	}
	// Implicit (no method) vs explicit HTTP method mappings
	// 通过method来比较。
	result = this.methodsCondition.compareTo(other.getMethodsCondition(), request);
	if (result != 0) {
		return result;
	}
	result = this.customConditionHolder.compareTo(other.customConditionHolder, request);
	if (result != 0) {
		return result;
	}
	return 0;
}

分别再分析下每个Condition中的compareTo方法,它们是实现比较的核心逻辑。
(1)、PatternsRequestCondition:根据请求路径比较。这个属性也是最开始进行比较的

@Override
public int compareTo(PatternsRequestCondition other, HttpServletRequest request) {
	// 获取本次请求的path
	String lookupPath = this.pathHelper.getLookupPathForRequest(request, HandlerMapping.LOOKUP_PATH);
	// 通过path获取Comparator,这里用的是PathMatcher的实现类AntPathMatcher里面的AntPatternComparator
	Comparator<String> patternComparator = this.pathMatcher.getPatternComparator(lookupPath);
	Iterator<String> iterator = this.patterns.iterator();
	Iterator<String> iteratorOther = other.patterns.iterator();
	// 通过AntPatternComparator进行比较。
	while (iterator.hasNext() && iteratorOther.hasNext()) {
		int result = patternComparator.compare(iterator.next(), iteratorOther.next());
		if (result != 0) {
			return result;
		}
	}
	if (iterator.hasNext()) {
		return -1;
	}
	else if (iteratorOther.hasNext()) {
		return 1;
	}
	else {
		return 0;
	}
}
@Override
public int compare(String pattern1, String pattern2) {
	PatternInfo info1 = new PatternInfo(pattern1);
	PatternInfo info2 = new PatternInfo(pattern2);

	if (info1.isLeastSpecific() && info2.isLeastSpecific()) {
		return 0;
	}
	else if (info1.isLeastSpecific()) {
		return 1;
	}
	else if (info2.isLeastSpecific()) {
		return -1;
	}

	boolean pattern1EqualsPath = pattern1.equals(this.path);
	boolean pattern2EqualsPath = pattern2.equals(this.path);
	if (pattern1EqualsPath && pattern2EqualsPath) {
		return 0;
	}
	else if (pattern1EqualsPath) {
		return -1;
	}
	else if (pattern2EqualsPath) {
		return 1;
	}

	if (info1.isPrefixPattern() && info2.isPrefixPattern()) {
		return info2.getLength() - info1.getLength();
	}
	else if (info1.isPrefixPattern() && info2.getDoubleWildcards() == 0) {
		return 1;
	}
	else if (info2.isPrefixPattern() && info1.getDoubleWildcards() == 0) {
		return -1;
	}

	if (info1.getTotalCount() != info2.getTotalCount()) {
		return info1.getTotalCount() - info2.getTotalCount();
	}

	if (info1.getLength() != info2.getLength()) {
		return info2.getLength() - info1.getLength();
	}

	if (info1.getSingleWildcards() < info2.getSingleWildcards()) {
		return -1;
	}
	else if (info2.getSingleWildcards() < info1.getSingleWildcards()) {
		return 1;
	}

	if (info1.getUriVars() < info2.getUriVars()) {
		return -1;
	}
	else if (info2.getUriVars() < info1.getUriVars()) {
		return 1;
	}

	return 0;
}

这里附上关于AntPathMatcher这个类的注释:

/**
 * {@link PathMatcher} implementation for Ant-style path patterns.
 *
 * <p>Part of this mapping code has been kindly borrowed from <a href="https://ant.apache.org">Apache Ant</a>.
 *
 * <p>The mapping matches URLs using the following rules:<br>
 * <ul>
 * <li>{@code ?} matches one character</li>
 * <li>{@code *} matches zero or more characters</li>
 * <li>{@code **} matches zero or more <em>directories</em> in a path</li>
 * <li>{@code {spring:[a-z]+}} matches the regexp {@code [a-z]+} as a path variable named "spring"</li>
 * </ul>
 *
 * <h3>Examples</h3>
 * <ul>
 * <li>{@code com/t?st.jsp} &mdash; matches {@code com/test.jsp} but also
 * {@code com/tast.jsp} or {@code com/txst.jsp}</li>
 * <li>{@code com/*.jsp} &mdash; matches all {@code .jsp} files in the
 * {@code com} directory</li>
 * <li><code>com/&#42;&#42;/test.jsp</code> &mdash; matches all {@code test.jsp}
 * files underneath the {@code com} path</li>
 * <li><code>org/springframework/&#42;&#42;/*.jsp</code> &mdash; matches all
 * {@code .jsp} files underneath the {@code org/springframework} path</li>
 * <li><code>org/&#42;&#42;/servlet/bla.jsp</code> &mdash; matches
 * {@code org/springframework/servlet/bla.jsp} but also
 * {@code org/springframework/testing/servlet/bla.jsp} and {@code org/servlet/bla.jsp}</li>
 * <li>{@code com/{filename:\\w+}.jsp} will match {@code com/test.jsp} and assign the value {@code test}
 * to the {@code filename} variable</li>
 * </ul>
 *
 * <p><strong>Note:</strong> a pattern and a path must both be absolute or must
 * both be relative in order for the two to match. Therefore it is recommended
 * that users of this implementation to sanitize patterns in order to prefix
 * them with "/" as it makes sense in the context in which they're used.
 *
 */

(2)、ParamsRequestCondition:根据请求参数进行比较。

@Override
public int compareTo(ParamsRequestCondition other, HttpServletRequest request) {
	// 主要是根据请求参数的多少进行判断,多的在前。
	int result = other.expressions.size() - this.expressions.size();
	if (result != 0) {
		return result;
	}
	return (int) (getValueMatchCount(other.expressions) - getValueMatchCount(this.expressions));
}

(3)、HeadersRequestCondition:根据请求头进行比较。

@Override
public int compareTo(HeadersRequestCondition other, HttpServletRequest request) {
	// 根据请求头多少进行判断,多的在前。
	int result = other.expressions.size() - this.expressions.size();
	if (result != 0) {
		return result;
	}
	return (int) (getValueMatchCount(other.expressions) - getValueMatchCount(this.expressions));
}

(4)、ConsumesRequestCondition:根据消息内容进行比较。

@Override
public int compareTo(ConsumesRequestCondition other, HttpServletRequest request) {
	// 如果两个比较的消息内容都为空,那么就认为相等
	if (this.expressions.isEmpty() && other.expressions.isEmpty()) {
		return 0;
	}
	// 如果“其他”有更多特定的媒体类型表达式,则大于0
	else if (this.expressions.isEmpty()) {
		return 1;
	}
	// 如果“this”有更多特定的媒体类型表达式,则小于0
	else if (other.expressions.isEmpty()) {
		return -1;
	}
	else {
		return this.expressions.get(0).compareTo(other.expressions.get(0));
	}
}

(5)、ProducesRequestCondition:根据接受类型进行比较。

@Override
public int compareTo(ProducesRequestCondition other, HttpServletRequest request) {
	try {
		// 首先获取本次请求的所有的可接受的类型
		List<MediaType> acceptedMediaTypes = getAcceptedMediaTypes(request);
		// 对这些类型进行迭代
		for (MediaType acceptedMediaType : acceptedMediaTypes) {
			// 获取this类型的type的索引
			int thisIndex = this.indexOfEqualMediaType(acceptedMediaType);
			// 获取other类型的type的索引
			int otherIndex = other.indexOfEqualMediaType(acceptedMediaType);
			比较两个类型的索引
			int result = compareMatchingMediaTypes(this, thisIndex, other, otherIndex);
			if (result != 0) {
				return result;
			}
			thisIndex = this.indexOfIncludedMediaType(acceptedMediaType);
			otherIndex = other.indexOfIncludedMediaType(acceptedMediaType);
			result = compareMatchingMediaTypes(this, thisIndex, other, otherIndex);
			if (result != 0) {
				return result;
			}
		}
		return 0;
	}
	catch (HttpMediaTypeNotAcceptableException ex) {
		// should never happen
		throw new IllegalStateException("Cannot compare without having any requested media types", ex);
	}
}

(6)、RequestMethodsRequestCondition:根据请求方法进行比较。

@Override
public int compareTo(RequestMethodsRequestCondition other, HttpServletRequest request) {
	if (other.methods.size() != this.methods.size()) {
		return other.methods.size() - this.methods.size();
	}
	else if (this.methods.size() == 1) {
		if (this.methods.contains(RequestMethod.HEAD) && other.methods.contains(RequestMethod.GET)) {
			return -1;
		}
	else if (this.methods.contains(RequestMethod.GET) && other.methods.contains(RequestMethod.HEAD)) {
		return 1;
		}
	}
	return 0;
}

这里同样也是根据方法的数目进行比较。

以上就是当存在多个匹配结果的时候进行排序的依据,排序完成之后会从取出第一个Match,获取其中的HandlerMethod,并封装成HandlerExecutionChain返回。

(3)、获取处理适配器
protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
	if (this.handlerAdapters != null) {
		// 循环判断当前的适配器是否支持Handler,如果支持则返回该适配器
		for (HandlerAdapter adapter : this.handlerAdapters) {
			if (adapter.supports(handler)) {
				return adapter;
			}
		}
	}
	throw new ServletException("No adapter for handler [" + handler +
				"]: The DispatcherServlet configuration needs to include a HandlerAdapter that supports this handler");
}

PS:handlerAdapters是在DispatcherServlet初始化的时候被注册进去的。
这里仍以RequestMappingHandlerAdapter为例。
该类的结构图如下:
image.png
RequestMappingHandlerAdapter实现了HandlerAdapter,该接口的方法如下:
image.png
(1)、是否支持Handler。
(2)、执行Handler。
(3)、获取上次的修改的时间。
RequestMappingHandlerAdapter类同样也分为两部分:
第一部分初始化操作
第二部分执行handler操作

RequestMappingHandlerAdapter的初始化操作
RequestMappingHandlerAdapter同时也实现了InitializingBean,那么它在被创建的时候也会调用afterPropertiesSet方法。

@Override
public void afterPropertiesSet() {
	// Do this first, it may add ResponseBody advice beans
	// 初始化被ControllerAdvice注解标记的类
	initControllerAdviceCache();
	// 初始化参数解析器
	if (this.argumentResolvers == null) {
		List<HandlerMethodArgumentResolver> resolvers = getDefaultArgumentResolvers();
		this.argumentResolvers = new HandlerMethodArgumentResolverComposite().addResolvers(resolvers);
	}
	// 初始化参数绑定器
	if (this.initBinderArgumentResolvers == null) {
		List<HandlerMethodArgumentResolver> resolvers = getDefaultInitBinderArgumentResolvers();
		this.initBinderArgumentResolvers = new HandlerMethodArgumentResolverComposite().addResolvers(resolvers);
	}
	// 初始化返回值处理器
	if (this.returnValueHandlers == null) {
		List<HandlerMethodReturnValueHandler> handlers = getDefaultReturnValueHandlers();
		this.returnValueHandlers = new HandlerMethodReturnValueHandlerComposite().addHandlers(handlers);
	}
}

最开始的时候会初始化ControllerAdvice,这里从相关资料上查找并介绍下这个注解的作用:
(1)、数据绑定:通过注解@InitBinder可以为数据绑定器WebDataBinder添加新的类型转化器。在所有需进行类型转换的参数绑定过程中,都需要用到WebDataBinder的数据转换功能把请求数据转换为目标参数类型。
(2)、异常处理:当处理器方法中发生异常且未被处理器捕获时,会通过异常处理器对该异常进行处理。通过@ExceptionHandler可以为处理器方法声明异常处理方法。
(3)、模型属性:通过在非处理器方法上标记@ModelAttribute,可以为所有的处理器方法附加模型属性。在执行处理器方法前先执行@ModelAttribute标记的方法,并添加该方法的返回值到Model中。
(4)、请求体与响应体增强:在@RequestBody与@ResponseBody的处理中增强信息转换功能,可以在读取请求体前,读请求体后,写相应器前对数据做一些特殊处理。

private void initControllerAdviceCache() {
	if (getApplicationContext() == null) {
		return;
	}

	List<ControllerAdviceBean> adviceBeans = ControllerAdviceBean.findAnnotatedBeans(getApplicationContext());

	List<Object> requestResponseBodyAdviceBeans = new ArrayList<>();

	for (ControllerAdviceBean adviceBean : adviceBeans) {
		Class<?> beanType = adviceBean.getBeanType();
		if (beanType == null) {
			throw new IllegalStateException("Unresolvable type for ControllerAdviceBean: " + adviceBean);
		}
		Set<Method> attrMethods = MethodIntrospector.selectMethods(beanType, MODEL_ATTRIBUTE_METHODS);
		if (!attrMethods.isEmpty()) {
			this.modelAttributeAdviceCache.put(adviceBean, attrMethods);
		}
		Set<Method> binderMethods = MethodIntrospector.selectMethods(beanType, INIT_BINDER_METHODS);
		if (!binderMethods.isEmpty()) {
			this.initBinderAdviceCache.put(adviceBean, binderMethods);
		}
		if (RequestBodyAdvice.class.isAssignableFrom(beanType) || ResponseBodyAdvice.class.isAssignableFrom(beanType)) {
			requestResponseBodyAdviceBeans.add(adviceBean);
		}
	}

	if (!requestResponseBodyAdviceBeans.isEmpty()) {
		this.requestResponseBodyAdvice.addAll(0, requestResponseBodyAdviceBeans);
	}

	if (logger.isDebugEnabled()) {
		int modelSize = this.modelAttributeAdviceCache.size();
		int binderSize = this.initBinderAdviceCache.size();
		int reqCount = getBodyAdviceCount(RequestBodyAdvice.class);
		int resCount = getBodyAdviceCount(ResponseBodyAdvice.class);
		if (modelSize == 0 && binderSize == 0 && reqCount == 0 && resCount == 0) {
			logger.debug("ControllerAdvice beans: none");
		}
		else {
			logger.debug("ControllerAdvice beans: " + modelSize + " @ModelAttribute, " + binderSize +
						" @InitBinder, " + reqCount + " RequestBodyAdvice, " + resCount + " ResponseBodyAdvice");
		}
	}
}

RequestMappingHandlerAdapter执行handler操作
执行handler操作是在AbstractHandlerMethodAdapter中进行的。

@Override
@Nullable
public final ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
			throws Exception {
	// 真正执行处理的方法,由子类覆盖。
	return handleInternal(request, response, (HandlerMethod) handler);
}

RequestMappingHandlerAdapter中的handleInternal:

@Override
protected ModelAndView handleInternal(HttpServletRequest request,
			HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {

	ModelAndView mav;
	// 校验request,如果支持的方法列表中不存在就抛出异常。
	checkRequest(request);

	// Execute invokeHandlerMethod in synchronized block if required.
	if (this.synchronizeOnSession) {
		HttpSession session = request.getSession(false);
		if (session != null) {
			Object mutex = WebUtils.getSessionMutex(session);
			synchronized (mutex) {
				mav = invokeHandlerMethod(request, response, handlerMethod);
			}
		}
		else {
			// No HttpSession available -> no mutex necessary
			mav = invokeHandlerMethod(request, response, handlerMethod);
		}
	}
	else {
		// No synchronization on session demanded at all...
		// 调用HandlerMethod方法。
		mav = invokeHandlerMethod(request, response, handlerMethod);
	}

	if (!response.containsHeader(HEADER_CACHE_CONTROL)) {
		if (getSessionAttributesHandler(handlerMethod).hasSessionAttributes()) {
			applyCacheSeconds(response, this.cacheSecondsForSessionAttributeHandlers);
		}
		else {
			prepareResponse(response);
		}
	}

	return mav;
}

invokeHandlerMethod方法代码如下:

@Nullable
protected ModelAndView invokeHandlerMethod(HttpServletRequest request,
			HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
	// 首先将请求封装成ServletWebRequest。
	ServletWebRequest webRequest = new ServletWebRequest(request, response);
	try {
		// 构建参数绑定器工厂,DataBinder的主要功能是将String类型的值转成相应的数据
		WebDataBinderFactory binderFactory = getDataBinderFactory(handlerMethod);
		// 构建ModelAttribute属性器工厂
		ModelFactory modelFactory = getModelFactory(handlerMethod, binderFactory);

		// 根据HandlerMethod对象构建ServletInvocableHandlerMethod
		ServletInvocableHandlerMethod invocableMethod = createInvocableHandlerMethod(handlerMethod);
		// 设置各种解析器
		if (this.argumentResolvers != null) {
			invocableMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers);
		}
		if (this.returnValueHandlers != null) {
			invocableMethod.setHandlerMethodReturnValueHandlers(this.returnValueHandlers);
		}
		invocableMethod.setDataBinderFactory(binderFactory);
		invocableMethod.setParameterNameDiscoverer(this.parameterNameDiscoverer);

		ModelAndViewContainer mavContainer = new ModelAndViewContainer();
		mavContainer.addAllAttributes(RequestContextUtils.getInputFlashMap(request));
		modelFactory.initModel(webRequest, mavContainer, invocableMethod);
		mavContainer.setIgnoreDefaultModelOnRedirect(this.ignoreDefaultModelOnRedirect);
		// 异步请求处理
		AsyncWebRequest asyncWebRequest = WebAsyncUtils.createAsyncWebRequest(request, response);
		asyncWebRequest.setTimeout(this.asyncRequestTimeout);

		WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
		asyncManager.setTaskExecutor(this.taskExecutor);
		asyncManager.setAsyncWebRequest(asyncWebRequest);
		asyncManager.registerCallableInterceptors(this.callableInterceptors);
		asyncManager.registerDeferredResultInterceptors(this.deferredResultInterceptors);

		if (asyncManager.hasConcurrentResult()) {
			Object result = asyncManager.getConcurrentResult();
			mavContainer = (ModelAndViewContainer) asyncManager.getConcurrentResultContext()[0];
			asyncManager.clearConcurrentResult();
			LogFormatUtils.traceDebug(logger, traceOn -> {
				String formatted = LogFormatUtils.formatValue(result, !traceOn);
				return "Resume with async result [" + formatted + "]";
			});
			invocableMethod = invocableMethod.wrapConcurrentResult(result);
		}
		// 执行调用HandlerMethod
		invocableMethod.invokeAndHandle(webRequest, mavContainer);
		if (asyncManager.isConcurrentHandlingStarted()) {
			return null;
		}
		// 将请求的结果封装成ModelAndView
		return getModelAndView(mavContainer, modelFactory, webRequest);
	}
	finally {
		webRequest.requestCompleted();
	}
}

通过上述流程完成了方法的调用,并将结果封装成ModelAndView。