SpringMVC源码-getHandler

DispatcherServlet.getHandler(HttpServletRequest request)

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

如果handlerMappings不为null,从handlerMappings中找出处理当前请求的HandlerExecutionChain并返回。handlerMappings集合的元素分别是RequestMappingHandlerMapping,BeanNameUrlHandlerMapping,SimpleUrlHandlerMapping。

一、RequestMappingHandlerMapping

AbstractHandlerMapping.getHandler(HttpServletRequest request)

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);
	}

	// Ensure presence of cached lookupPath for interceptors and others
	if (!ServletRequestPathUtils.hasCachedPath(request)) {
		initLookupPath(request);
	}

	HandlerExecutionChain executionChain = getHandlerExecutionChain(handler, request);

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

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

	return executionChain;
}

1、getHandlerInternal获取handle,如果handle为null则getDefaultHandler获取默认handle,handle还为null返回。
2、如果handle是String,handle可能为beanName,调用getBean获取bean
3、如果拦截器没有缓存查找路径就initLookupPath解析拦截器路径并缓存。
4、获取HandlerExecutionChain
5、如果有CORS配置则处理CORS

RequestMappingInfoHandlerMapping.getHandlerInternal(HttpServletRequest request)

protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {
	request.removeAttribute(PRODUCIBLE_MEDIA_TYPES_ATTRIBUTE);
	try {
		return super.getHandlerInternal(request);
	}
	finally {
		ProducesRequestCondition.clearMediaTypesAttribute(request);
	}
}

AbstractHandlerMethodMapping.getHandlerInternal(HttpServletRequest request)

protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {
	String lookupPath = initLookupPath(request);
	this.mappingRegistry.acquireReadLock();
	try {
		HandlerMethod handlerMethod = lookupHandlerMethod(lookupPath, request);
		return (handlerMethod != null ? handlerMethod.createWithResolvedBean() : null);
	}
	finally {
		this.mappingRegistry.releaseReadLock();
	}
}

1、initLookupPath查找request请求路径
2、lookupHandlerMethod查找请求路径处理方法HandlerMethod
3、如果HandlerMethod不为null则handlerMethod.createWithResolvedBean解析处理方法对应的bean。

AbstractHandlerMethodMapping.initLookupPath(HttpServletRequest request)

protected String initLookupPath(HttpServletRequest request) {
	if (usesPathPatterns()) {
		request.removeAttribute(UrlPathHelper.PATH_ATTRIBUTE);
		RequestPath requestPath = ServletRequestPathUtils.getParsedRequestPath(request);
		String lookupPath = requestPath.pathWithinApplication().value();
		return UrlPathHelper.defaultInstance.removeSemicolonContent(lookupPath);
	}
	else {
		return getUrlPathHelper().resolveAndCacheLookupPath(request);
	}
}

1、如果usesPathPatterns()为true,调用ServletRequestPathUtils.getParsedRequestPath解析lookupPath。usesPathPatterns()默认为false。
2、调用getUrlPathHelper().resolveAndCacheLookupPath解析lookupPath

UrlPathHelper.resolveAndCacheLookupPath(HttpServletRequest request)

public String resolveAndCacheLookupPath(HttpServletRequest request) {
	String lookupPath = getLookupPathForRequest(request);
	request.setAttribute(PATH_ATTRIBUTE, lookupPath);
	return lookupPath;
}

1、getLookupPathForRequest解析request对应的请求路径
2、PATH_ATTRIBUTE为key,请求路径lookupPath为value设置属性到request中

UrlPathHelper.getLookupPathForRequest(HttpServletRequest request)

  public String getLookupPathForRequest(HttpServletRequest request) {
	String pathWithinApp = getPathWithinApplication(request);
	// Always use full path within current servlet context?
	if (this.alwaysUseFullPath || skipServletPathDetermination(request)) {
		return pathWithinApp;
	}
	// Else, use path within current servlet mapping if applicable
	String rest = getPathWithinServletMapping(request, pathWithinApp);
	if (StringUtils.hasLength(rest)) {
		return rest;
	}
	else {
		return pathWithinApp;
	}
}

1、getPathWithinApplication从request中返回请求路径
2、如果使用全路径或skipServletPathDetermination为true则返回,skipServletPathDetermination检查是否可跳过请求路径
3、getPathWithinServletMapping使用当前Servlet中映射的路径

UrlPathHelper.getPathWithinApplication(HttpServletRequest request)

public String getPathWithinApplication(HttpServletRequest request) {
	String contextPath = getContextPath(request);
	String requestUri = getRequestUri(request);
	String path = getRemainingPath(requestUri, contextPath, true);
	if (path != null) {
		// Normal case: URI contains context path.
		return (StringUtils.hasText(path) ? path : "/");
	}
	else {
		return requestUri;
	}
}

1、getContextPath从request获取contextPath
2、getRequestUri从request获取requestUri
3、getRemainingPath从requestUri中去掉contextPath剩余部分,如requestUri为/myself-web/userParam0,contextPath为/myself-web,getRemainingPath(requestUri, contextPath, true)结果为/userParam0

UrlPathHelper.getContextPath(HttpServletRequest request)

public String getContextPath(HttpServletRequest request) {
	String contextPath = (String) request.getAttribute(WebUtils.INCLUDE_CONTEXT_PATH_ATTRIBUTE);
	if (contextPath == null) {
		contextPath = request.getContextPath();
	}
	if (StringUtils.matchesCharacter(contextPath, '/')) {
		// Invalid case, but happens for includes on Jetty: silently adapt it.
		contextPath = "";
	}
	return decodeRequestString(request, contextPath);
}

1、从request中获取INCLUDE_CONTEXT_PATH_ATTRIBUTE属性,如果为null则从request中获取contextPath
2、decodeRequestString解码contextPath

UrlPathHelper.getRequestUri(HttpServletRequest request)

public String getRequestUri(HttpServletRequest request) {
	String uri = (String) request.getAttribute(WebUtils.INCLUDE_REQUEST_URI_ATTRIBUTE);
	if (uri == null) {
		uri = request.getRequestURI();
	}
	return decodeAndCleanUriString(request, uri);
}

1、从request中获取INCLUDE_REQUEST_URI_ATTRIBUTE属性,如果为null则从request中获取RequestURI
2、decodeAndCleanUriString解码RequestURI

UrlPathHelper.skipServletPathDetermination(HttpServletRequest request)

private boolean skipServletPathDetermination(HttpServletRequest request) {
	if (servlet4Present) {
		return Servlet4Delegate.skipServletPathDetermination(request);
	}
	return false;
}

如果servlet4Present为true,调用Servlet4Delegate.skipServletPathDetermination检查是否可跳过请求路径,否则返回false。

Servlet4Delegate.skipServletPathDetermination(HttpServletRequest request)

public static boolean skipServletPathDetermination(HttpServletRequest request) {
		HttpServletMapping mapping = (HttpServletMapping) request.getAttribute(RequestDispatcher.INCLUDE_MAPPING);
		if (mapping == null) {
			mapping = request.getHttpServletMapping();
		}
		MappingMatch match = mapping.getMappingMatch();
		return (match != null && (!match.equals(MappingMatch.PATH) || mapping.getPattern().equals("/*")));
	}

获取MappingMatch,判断MappingMatch是否匹配MappingMatch.PATH(MappingMatch.PATH是/faces/这种的映射路径)和HttpServletMapping获取pattern是否和/相等。

AbstractHandlerMethodMapping.lookupHandlerMethod(String lookupPath, HttpServletRequest request)

protected HandlerMethod lookupHandlerMethod(String lookupPath, HttpServletRequest request) throws Exception {
	List<Match> matches = new ArrayList<>();
	List<T> directPathMatches = this.mappingRegistry.getMappingsByDirectPath(lookupPath);
	if (directPathMatches != null) {
		addMatchingMappings(directPathMatches, matches, request);
	}
	if (matches.isEmpty()) {
		addMatchingMappings(this.mappingRegistry.getRegistrations().keySet(), matches, request);
	}
	if (!matches.isEmpty()) {
		Match bestMatch = matches.get(0);
		if (matches.size() > 1) {
			Comparator<Match> comparator = new MatchComparator(getMappingComparator(request));
			matches.sort(comparator);
			bestMatch = matches.get(0);
			if (logger.isTraceEnabled()) {
				logger.trace(matches.size() + " matching mappings: " + matches);
			}
			if (CorsUtils.isPreFlightRequest(request)) {
				for (Match match : matches) {
					if (match.hasCorsConfig()) {
						return PREFLIGHT_AMBIGUOUS_MATCH;
					}
				}
			}
			else {
				Match secondBestMatch = matches.get(1);
				if (comparator.compare(bestMatch, secondBestMatch) == 0) {
					Method m1 = bestMatch.getHandlerMethod().getMethod();
					Method m2 = secondBestMatch.getHandlerMethod().getMethod();
					String uri = request.getRequestURI();
					throw new IllegalStateException(
							"Ambiguous handler methods mapped for '" + uri + "': {" + m1 + ", " + m2 + "}");
				}
			}
		}
		request.setAttribute(BEST_MATCHING_HANDLER_ATTRIBUTE, bestMatch.getHandlerMethod());
		handleMatch(bestMatch.mapping, lookupPath, request);
		return bestMatch.getHandlerMethod();
	}
	else {
		return handleNoMatch(this.mappingRegistry.getRegistrations().keySet(), lookupPath, request);
	}
}

1、mappingRegistry.getMappingsByDirectPath通过请求路径获取RequestMappingInfo集合,mappingRegistry.getMappingsByDirectPath只能获取请求路径中不存在模式的路径,即路径中不存在*,{}.
2、如果请求路径中不存在模式,调用addMatchingMappings添加Match集合
3、如果matches为空,即请求路径存在模式,调用addMatchingMappings从mappingRegistry.getRegistrations().keySet()(包含所有请求方法处理的RequestMappingInfo集合)中添加Match匹配request的集合
4、如果matches集合非空,查找最匹配的Match,调用handleMatch处理Match。handleMatch在请求中公开URI模板变量、矩阵变量和可生产的媒体类型。如果matches集合为空,handleNoMatch处理没有Match的情况。

AbstractHandlerMethodMapping.addMatchingMappings(Collection mappings, List matches, HttpServletRequest request)

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.getRegistrations().get(mapping)));
		}
	}
}

遍历mappings集合,即封装了@Controller类中@RequestMapping标注的方法集合,getMatchingMapping返回匹配请求的RequestMappingInfo加到Match集合中。

RequestMappingInfoHandlerMapping.getMatchingMapping(RequestMappingInfo info, HttpServletRequest request)

protected RequestMappingInfo getMatchingMapping(RequestMappingInfo info, HttpServletRequest request) {
	return info.getMatchingCondition(request);
}

返回匹配请求的RequestMappingInfo。

RequestMappingInfo.getMatchingCondition(HttpServletRequest request)

public RequestMappingInfo getMatchingCondition(HttpServletRequest request) {
	RequestMethodsRequestCondition methods = this.methodsCondition.getMatchingCondition(request);
	if (methods == null) {
		return null;
	}
	ParamsRequestCondition params = this.paramsCondition.getMatchingCondition(request);
	if (params == null) {
		return null;
	}
	HeadersRequestCondition headers = this.headersCondition.getMatchingCondition(request);
	if (headers == null) {
		return null;
	}
	ConsumesRequestCondition consumes = this.consumesCondition.getMatchingCondition(request);
	if (consumes == null) {
		return null;
	}
	ProducesRequestCondition produces = this.producesCondition.getMatchingCondition(request);
	if (produces == null) {
		return null;
	}
	PathPatternsRequestCondition pathPatterns = null;
	if (this.pathPatternsCondition != null) {
		pathPatterns = this.pathPatternsCondition.getMatchingCondition(request);
		if (pathPatterns == null) {
			return null;
		}
	}
	PatternsRequestCondition patterns = null;
	if (this.patternsCondition != null) {
		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, pathPatterns, patterns,
			methods, params, headers, consumes, produces, custom, this.options);
}

依次调用methodsCondition,paramsCondition,headersCondition,consumesCondition,producesCondition,pathPatternsCondition,patternsCondition,customConditionHolder去匹配请求。当请求路径存在模式时由patternsCondition(PatternsRequestCondition)匹配请求路径。

PatternsRequestCondition.getMatchingCondition(HttpServletRequest request)

  public PatternsRequestCondition getMatchingCondition(HttpServletRequest request) {
	String lookupPath = UrlPathHelper.getResolvedLookupPath(request);
	List<String> matches = getMatchingPatterns(lookupPath);
	return !matches.isEmpty() ? new PatternsRequestCondition(new LinkedHashSet<>(matches), this) : null;
}

1、获取request中的请求路径
2、将request中的请求路径与@RequestMapping标注的URL进行模式匹配。若匹配返回PatternsRequestCondition否则返回null。调用PathMatcher.match(String pattern, String path)判断请求是否与模式匹配,即与@RequestMapping中的URL模式是否匹配。

RequestMappingInfoHandlerMapping.handleMatch(RequestMappingInfo info, String lookupPath, HttpServletRequest request)

protected void handleMatch(RequestMappingInfo info, String lookupPath, HttpServletRequest request) {
	super.handleMatch(info, lookupPath, request);

	RequestCondition<?> condition = info.getActivePatternsCondition();
	if (condition instanceof PathPatternsRequestCondition) {
		extractMatchDetails((PathPatternsRequestCondition) condition, lookupPath, request);
	}
	else {
		extractMatchDetails((PatternsRequestCondition) condition, lookupPath, request);
	}

	if (!info.getProducesCondition().getProducibleMediaTypes().isEmpty()) {
		Set<MediaType> mediaTypes = info.getProducesCondition().getProducibleMediaTypes();
		request.setAttribute(PRODUCIBLE_MEDIA_TYPES_ATTRIBUTE, mediaTypes);
	}
}

1、调用父类的handleMatch。request.setAttribute(HandlerMapping.PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE, lookupPath);将请求路径设置PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE属性中。
2、获取RequestCondition,如果RequestCondition是PathPatternsRequestCondition类型进行处理。否则将RequestCondition转成PatternsRequestCondition后进行处理。
3、解析producible media types并设置到属性中

RequestMappingInfoHandlerMapping.extractMatchDetails(
PatternsRequestCondition condition, String lookupPath, HttpServletRequest request)

private void extractMatchDetails(
		PatternsRequestCondition condition, String lookupPath, HttpServletRequest request) {

	String bestPattern;
	Map<String, String> uriVariables;
	if (condition.isEmptyPathMapping()) {
		bestPattern = lookupPath;
		uriVariables = Collections.emptyMap();
	}
	else {
		bestPattern = condition.getPatterns().iterator().next();
		uriVariables = getPathMatcher().extractUriTemplateVariables(bestPattern, lookupPath);
		if (!getUrlPathHelper().shouldRemoveSemicolonContent()) {
			request.setAttribute(MATRIX_VARIABLES_ATTRIBUTE, extractMatrixVariables(request, uriVariables));
		}
		uriVariables = getUrlPathHelper().decodePathVariables(request, uriVariables);
	}
	request.setAttribute(BEST_MATCHING_PATTERN_ATTRIBUTE, bestPattern);
	request.setAttribute(URI_TEMPLATE_VARIABLES_ATTRIBUTE, uriVariables);
}

1、判断PatternsRequestCondition中处理请求路径是否非空,若为空uriVariables设置空集合。
2、获取pathMatcher解析UriTemplateVariables,@@PathVariable就是在这里解析值的。
3、设置最匹配路径到request的BEST_MATCHING_PATTERN_ATTRIBUTE属性中
4、设置uri模板变量值到request的URI_TEMPLATE_VARIABLES_ATTRIBUTE属性中

AntPathMatcher.extractUriTemplateVariables(String pattern, String path)

public Map<String, String> extractUriTemplateVariables(String pattern, String path) {
	Map<String, String> variables = new LinkedHashMap<>();
	boolean result = doMatch(pattern, path, true, variables);
	if (!result) {
		throw new IllegalStateException("Pattern \"" + pattern + "\" is not a match for \"" + path + "\"");
	}
	return variables;
}

将pattern和请求路径匹配,同时解析uri模板变量设置到Map中。比如,模式是/hotels/{hotel},路径是/hotels/1,Map的结果是hotel->1

AbstractHandlerMapping.getHandlerExecutionChain(Object handler, HttpServletRequest request)

	protected HandlerExecutionChain getHandlerExecutionChain(Object handler, HttpServletRequest request) {
	HandlerExecutionChain chain = (handler instanceof HandlerExecutionChain ?
			(HandlerExecutionChain) handler : new HandlerExecutionChain(handler));

	for (HandlerInterceptor interceptor : this.adaptedInterceptors) {
		if (interceptor instanceof MappedInterceptor) {
			MappedInterceptor mappedInterceptor = (MappedInterceptor) interceptor;
			if (mappedInterceptor.matches(request)) {
				chain.addInterceptor(mappedInterceptor.getInterceptor());
			}
		}
		else {
			chain.addInterceptor(interceptor);
		}
	}
	return chain;
}

1、创建HandlerExecutionChain
2、遍历adaptedInterceptors,如果interceptor是MappedInterceptor类型且匹配request,则获取Interceptor加入到HandlerExecutionChain,如果interceptor不是MappedInterceptor类型加入HandlerExecutionChain。

posted @   shigp1  阅读(193)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· Docker 太简单,K8s 太复杂?w7panel 让容器管理更轻松!
点击右上角即可分享
微信分享提示