栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

Spring Web HandlerMapping 笔记

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Spring Web HandlerMapping 笔记

HandlerMapping 介绍

HandlerMapping 用于将请求映射到 handler,以及前置处理拦截器和后置处理拦截器。该映射基于某些规则,其中的细节随着 HandlerMapping 的实现有所不同。

两个主要的 HandlerMapping 的实现类:

(1) RequestMappingHandlerMapping ,它支持 @RequestMapping 注解的方法

(2) SimpleUrlHandlerMapping,它维护 URI 路径模式到 handler 的指定注册

参考官方文档 1.1.2. Special Bean Types

Spring Boot

默认情况下,Spring Boot 提供 5 个默认的 HandlerMapping,他们分别是:

  • RequestMappingHandlerMapping
  • BeanNameUrlHandlerMapping
  • RouterFunctionMapping
  • SimpleUrlHandlerMapping
  • WelcomePageHandlerMapping

上述这几个 HandlerMapping 都是在 WebMvcAutoConfiguration 内部类 EnableWebMvcConfiguration 中配置的。

为了能够通过类名立即能知道该类实现了 HandlerMapping 接口,这些实现类都以 HandlerMapping 为结尾,以前缀标识其作用。

如何找到当前请求使用哪个 HandlerMapping 处理?

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

AbstractHandlerMapping 是所有 HandlerMapping 的父类,以下是所有请求获取 handler 的统一入口。

public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
	// getHandlerInternal 是抽象方法,留给子类实现
	
	Object handler = getHandlerInternal(request);
	// 如果子类无法找到 handler 则使用默认 handler
	if (handler == null) {
		handler = getDefaultHandler();
	}
	// 如果没有默认 handler,则返回 null
	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 (CorsUtils.isCorsRequest(request)) {
		CorsConfiguration globalConfig = this.globalCorsConfigSource.getCorsConfiguration(request);
		CorsConfiguration handlerConfig = getCorsConfiguration(handler, request);
		CorsConfiguration config = (globalConfig != null ? globalConfig.combine(handlerConfig) : handlerConfig);
		executionChain = getCorsHandlerExecutionChain(request, executionChain, config);
	}
	return executionChain;
}

getHandlerInternal 是抽象方法,由子类实现,因此官方才会有这样一句话:

The mapping is based on some criteria, the details of which vary by HandlerMapping implementation.

RequestMappingHandlerMapping

RequestMappingHandlerMapping 是 RequestMappingInfoHandlerMapping 的子类。RequestMappingInfoHandlerMapping 实现了 getHandlerInternal:

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

RequestMappingInfoHandlerMapping 并没有做什么具体的操作,他只是调用父类 AbstractHandlerMethodMapping 的 getHandlerInternal 方法:

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

上述代码比较重要的是 lookupHandlerMethod 方法调用,它负责寻找 handler 方法:

protected HandlerMethod lookupHandlerMethod(String lookupPath, HttpServletRequest request) throws Exception {
	List matches = new ArrayList<>();
	// 先通过 url 找到匹配项
	List directPathMatches = this.mappingRegistry.getMappingsByUrl(lookupPath);
	// 接着添加匹配的映射(根据具体条件,如 HTTP Method 等)
	if (directPathMatches != null) {
		addMatchingMappings(directPathMatches, matches, request);
	}
	if (matches.isEmpty()) {
		// No choice but to go through all mappings...
		addMatchingMappings(this.mappingRegistry.getMappings().keySet(), matches, request);
	}

	if (!matches.isEmpty()) {
		Match bestMatch = matches.get(0);

		// 如果匹配项不止 1 个
		if (matches.size() > 1) {	
			Comparator comparator = new MatchComparator(getMappingComparator(request));
			// 排序,取出第 0 个
			matches.sort(comparator);
			bestMatch = matches.get(0);
			if (logger.isTraceEnabled()) {
				logger.trace(matches.size() + " matching mappings: " + matches);
			}
			if (CorsUtils.isPreFlightRequest(request)) {
				return PREFLIGHT_AMBIGUOUS_MATCH;
			}
			Match secondBestMatch = matches.get(1);
			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);
	}
}

上述代码具体做的就是找到一个最佳匹配 handlerMethod 并返回,如果有两个并列的最佳匹配 handlerMethod,则抛出异常,Spring 无法决定选择哪个,因此,建议不要定义具有歧义的 handler。

SimpleUrlHandlerMapping

尽管类名称叫 SimpleUrlHandlerMapping,但是其 beanName 为 resourceHandlerMapping

SimpleUrlHandlerMapping 是 AbstractUrlHandlerMapping 的子类,直接使用其 getHandlerInternal 方法:

protected Object getHandlerInternal(HttpServletRequest request) throws Exception {
	// 获得需要寻找的路径
	String lookupPath = getUrlPathHelper().getLookupPathForRequest(request);
	request.setAttribute(LOOKUP_PATH, lookupPath);
	// 寻找 handler
	Object handler = lookupHandler(lookupPath, request);
	if (handler == null) {
		// 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 instanceof String) {
				String handlerName = (String) rawHandler;
				rawHandler = obtainApplicationContext().getBean(handlerName);
			}
			validateHandler(rawHandler, request);
			handler = buildPathExposingHandler(rawHandler, lookupPath, lookupPath, null);
		}
	}
	return handler;
}
protected Object lookupHandler(String urlPath, HttpServletRequest request) throws Exception {
	// Direct match?
	Object handler = this.handlerMap.get(urlPath);
	if (handler != null) {
		// Bean name or resolved handler?
		if (handler instanceof String) {
			String handlerName = (String) handler;
			handler = obtainApplicationContext().getBean(handlerName);
		}
		validateHandler(handler, request);
		return buildPathExposingHandler(handler, urlPath, urlPath, null);
	}

	// Pattern match?
	List matchingPatterns = new ArrayList<>();
	for (String registeredPattern : this.handlerMap.keySet()) {
		if (getPathMatcher().match(registeredPattern, urlPath)) {
			matchingPatterns.add(registeredPattern);
		}
		else if (useTrailingSlashMatch()) {
			if (!registeredPattern.endsWith("/") && getPathMatcher().match(registeredPattern + "/", urlPath)) {
				matchingPatterns.add(registeredPattern + "/");
			}
		}
	}

	String bestMatch = null;
	Comparator patternComparator = getPathMatcher().getPatternComparator(urlPath);
	if (!matchingPatterns.isEmpty()) {
		matchingPatterns.sort(patternComparator);
		if (logger.isTraceEnabled() && matchingPatterns.size() > 1) {
			logger.trace("Matching patterns " + matchingPatterns);
		}
		bestMatch = matchingPatterns.get(0);
	}
	if (bestMatch != null) {
		handler = this.handlerMap.get(bestMatch);
		if (handler == null) {
			if (bestMatch.endsWith("/")) {
				handler = this.handlerMap.get(bestMatch.substring(0, bestMatch.length() - 1));
			}
			if (handler == null) {
				throw new IllegalStateException(
						"Could not find handler for best pattern match [" + bestMatch + "]");
			}
		}
		// Bean name or resolved handler?
		if (handler instanceof String) {
			String handlerName = (String) handler;
			handler = obtainApplicationContext().getBean(handlerName);
		}
		validateHandler(handler, request);
		String pathWithinMapping = getPathMatcher().extractPathWithinPattern(bestMatch, urlPath);

		// There might be multiple 'best patterns', let's make sure we have the correct URI template variables
		// for all of them
		Map uriTemplateVariables = new LinkedHashMap<>();
		for (String matchingPattern : matchingPatterns) {
			if (patternComparator.compare(bestMatch, matchingPattern) == 0) {
				Map vars = getPathMatcher().extractUriTemplateVariables(matchingPattern, urlPath);
				Map decodedVars = getUrlPathHelper().decodePathVariables(request, vars);
				uriTemplateVariables.putAll(decodedVars);
			}
		}
		if (logger.isTraceEnabled() && uriTemplateVariables.size() > 0) {
			logger.trace("URI variables " + uriTemplateVariables);
		}
		return buildPathExposingHandler(handler, bestMatch, pathWithinMapping, uriTemplateVariables);
	}

	// No handler found...
	return null;
}
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/894560.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号