欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

java源码 - SpringMVC(4)之 HandlerMapping

程序员文章站 2022-05-18 18:17:40
5.2.4.RELEASE文章目录1. 类关系依赖图与继承关系2. AbstractHandlerMapping2.1 初始化2.2 使用3. AbstractUrlHandlerMappingtodo1. 类关系依赖图与继承关系主要看红线的,即如下继承关系:2. AbstractHandlerMapping还是见了很多次的模板模式,AbstractHandlerMapping设计了HandlerMa....

<spring.version>5.2.4.RELEASE</spring.version>

1. 类关系依赖图与继承关系

java源码 - SpringMVC(4)之 HandlerMapping
主要看红线的,即如下继承关系:
java源码 - SpringMVC(4)之 HandlerMapping

2. AbstractHandlerMapping

还是见了很多次的模板模式,AbstractHandlerMapping设计了HandlerMapping实现的整体结构,子类只需要通过模板方法提供一些初始值或者具体的实现。
HandlerMapping的作用是根据request查找Handler和Interceptors。获取Handler的过程通过模板方法getHandlerInternal交给了子类。AbstractHandlerMapping中保存了所用配置的Interceptor,在获取到Handler后会自己根据从request提取的lookupPath将相应的Inte-rceptors装配上去,当然子类也可以通过getHandlerInternal方法设置自己的Interceptor,getHandlerInternal的返回值为Object类型。

2.1 初始化

AbstractHandlerMapping继承了WebApplicationObjectSupport,初始化时会自动调用模板方法initApplicationContext,AbstractHandlerMapping的创建就是在initApplicationContext方法里面实现的。

	@Override
	protected void initApplicationContext() throws BeansException {		//钩子函数留给子类实现,将子类添加的拦截器加入到interceptors
		extendInterceptors(this.interceptors);
		//detectMappedInterceptors方法用于将Spring MVC容器及父容器中的所有MappedInter-ceptor类型的Bean添加到adaptedInterceptors属性
		detectMappedInterceptors(this.adaptedInterceptors);
		//initInterceptors方法的作用是初始化Interceptor,具体内容其实是将interceptors属性里所包含的对象按类型添加到adaptedInterceptors
		initInterceptors();
	}
	/ * *
	*子类可以覆盖的扩展钩子来注册额外的拦截器,
	*给定配置的拦截器(参见{@link #setInterceptors})*
	*将在{@link #initInterceptors()}调整指定的代码之前被调用
	*拦截器到{@link HandlerInterceptor}实例。
	*
	默认实现为空。
	* @param拦截器配置的拦截器列表(从不{@code null}),允许
	*在现有的拦截器之前和之后添加更多的拦截器
* /
	protected void extendInterceptors(List<Object> interceptors) {
	}
	/ * *
	*检测类型为{@link MappedInterceptor}的bean,并将其添加到映射的拦截器列表中。
	*
	这是在任何{@link MappedInterceptor MappedInterceptors}之外被调用的,可能已经提供
	*通过{@link #setInterceptors},默认情况下添加所有类型为{@link MappedInterceptor}的bean
	*从当前上下文及其祖先。子类可以重写和改进这个策略。
	添加{@link MappedInterceptor}实例到的空列表
* /
	protected void detectMappedInterceptors(List<HandlerInterceptor> mappedInterceptors) {
		mappedInterceptors.addAll(
				BeanFactoryUtils.beansOfTypeIncludingAncestors(
						obtainApplicationContext(), MappedInterceptor.class, true, false).values());
	}
	/ * *
	*初始化指定的拦截器,检查{@link MappedInterceptor}*适应{@link HandlerInterceptor}{@link WebRequestInterceptor HandlerInterceptor}* {@link WebRequestInterceptor}如果需要的话。
	* @see # setInterceptors
	* @see # adaptInterceptor
	* /
	protected void initInterceptors() {
		if (!this.interceptors.isEmpty()) {
			for (int i = 0; i < this.interceptors.size(); i++) {
				Object interceptor = this.interceptors.get(i);
				if (interceptor == null) {
					throw new IllegalArgumentException("Entry number " + i + " in interceptors array is null");
				}
				this.adaptedInterceptors.add(adaptInterceptor(interceptor));
			}
		}
	}

5.x 没有mappedInterceptors
mappedInterceptors:此类Interceptor在使用时需要与请求的url进行匹配,只有匹配成功后才会添加到getHandler的返回值HandlerExecutionChain里。它有两种获取途径:从interceptors获取或者注册到spring的容器中通过detectMappedInterceptors方法获取。

AbstractHandlerMapping中的Interceptor有三个List类型的属性:interceptors、adaptedInterceptors;

  • Interceptors:用于配置Spring MVC的拦截器,有两种设置方式:①注册Handler-Mapping时通过属性设置;②通过子类的extendInterceptors钩子方法进行设置。Interceptors并不会直接使用,而是通过initInterceptors方法按类型分配到adaptedInterceptors中进行使用,Interceptors只用于配置。

  • adaptedInterceptors:这种类型的Interceptor不需要进行匹配,在getHandler中会全部添加到返回值HandlerExecutionChain里面。它只能从interceptors中获取。

2.2 使用

HandlerMapping是通过getHandler方法来获取处理器Handler和拦截器Interceptor的。

	/ * *
	*查找给定请求的处理程序,返回到默认值
	*处理程序,如果没有找到特定的。
	* @param请求当前HTTP请求
	返回对应的处理程序实例,或默认处理程序
	* @see # getHandlerInternal
	* /
	@Override
	@Nullable
	public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
		//又是一个模板方法,获取Handler
		Object handler = getHandlerInternal(request);
		if (handler == null) {
		//如果没有就使用默认的Handler
		//默认的Handler保存在AbstractHandler-Mapping的一个Object类型的属性defaultHandler中
			handler = getDefaultHandler();
		}
		if (handler == null) {
			return null;
		}
		// Bean名称还是解析处理程序?
		if (handler instanceof String) {
			String handlerName = (String) handler;
		//如果找到的Handler是String类型,则以它为名到Spring MVC的容器里查找相应的Bean。
			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 (CorsUtils.isCorsRequest(request)) {
			CorsConfiguration globalConfig = this.corsConfigurationSource.getCorsConfiguration(request);
			CorsConfiguration handlerConfig = getCorsConfiguration(handler, request);
			CorsConfiguration config = (globalConfig != null ? globalConfig.combine(handlerConfig) : handlerConfig);
			executionChain = getCorsHandlerExecutionChain(request, executionChain, config);
		}

		return executionChain;
	}
	/**
	*查找给定请求的处理程序,如果没有,返回{@code null}
	*找到了特定的一个。该方法由{@link #getHandler}调用;
	*一个{@code null}返回值将导致默认处理程序,如果设置了一个。
	对于CORS飞行前请求,此方法应该返回一个不匹配的
	*飞行前的请求,但基于URL的预期实际请求
	*路径,从“访问-控制-请求-方法”头的HTTP方法,和
	*来自“访问-控制-请求-报头”的报头因此允许
	* CORS配置通过{@link #getCorsConfiguration(Object, HttpServletRequest)}获得,
	注意:此方法也可能返回预先构建的{@link HandlerExecutionChain},
	*将处理程序对象与动态确定的拦截程序相结合。
	*静态指定的拦截器将合并到这样一个已有的链中。
	* @param请求当前HTTP请求
	* @返回相应的处理程序实例,如果没有找到,则返回{@code null}
	* @抛出异常,如果有内部错误
	*/
	@Nullable
	protected abstract Object getHandlerInternal(HttpServletRequest request) throws Exception;

java源码 - SpringMVC(4)之 HandlerMapping
接下来看:

/**
	*为给定的处理程序构建{@link HandlerExecutionChain},包括
	*适用的拦截器。
	默认实现构建一个标准的{@link HandlerExecutionChain}
	*与给定的处理程序,处理程序映射的常见拦截器,和任何
	匹配当前请求URL。拦截器
	*按注册顺序添加。子类可以覆盖它
	*为了扩展/重新排列拦截器列表。
	注意:传递进来的处理程序对象可以是原始处理程序或a
	*预构建的{@link HandlerExecutionChain}。这个方法应该处理这些
	*显式地使用两种情况,要么构建一个新的{@link HandlerExecutionChain}
	*或扩展现有的链。
	如果只是在自定义子类中添加拦截器,请考虑调用
	* {@code超级。getHandlerExecutionChain(处理器,请求)}和调用
	在返回的链对象上* {@link HandlerExecutionChain#addInterceptor}。
	解析的处理程序实例(never {@code null})
	* @param请求当前HTTP请求
	* @return HandlerExecutionChain (never {@code null})
	* @see # getAdaptedInterceptors ()
	*/
	protected HandlerExecutionChain getHandlerExecutionChain(Object handler, HttpServletRequest request) {
		HandlerExecutionChain chain = (handler instanceof HandlerExecutionChain ?
				(HandlerExecutionChain) handler : new HandlerExecutionChain(handler));
		//提取出路径
		String lookupPath = this.urlPathHelper.getLookupPathForRequest(request);
		
		for (HandlerInterceptor interceptor : this.adaptedInterceptors) {
		//找到匹配的interceptor 
			if (interceptor instanceof MappedInterceptor) {
				MappedInterceptor mappedInterceptor = (MappedInterceptor) interceptor;
				//等于找到对应该路径的拦截器
				if (mappedInterceptor.matches(lookupPath, this.pathMatcher)) {
					chain.addInterceptor(mappedInterceptor.getInterceptor());
				}
			}
			else {
			//否则就是全局拦截器,加入执行链
				chain.addInterceptor(interceptor);
			}
		}
		return chain;
	}

再来看看MappedInterceptor 是个什么东西:

/*
*包含并委托对{@link HandlerInterceptor}的调用
*包括(可选排除)拦截器应该应用的路径模式。
*还提供了匹配逻辑来测试拦截器是否适用于给定的请求路径。
MappedInterceptor可以直接注册到any
* {@link org.springframework.web.servlet.handler.AbstractHandlerMethodMapping}。
*此外,类型为{@code MappedInterceptor}的bean被自动检测
* {@code AbstractHandlerMethodMapping}(包括祖先ApplicationContext的)
*有效地意味着拦截器注册为“全局”的所有处理程序映射。
*/
public final class MappedInterceptor implements HandlerInterceptor {

看注释可见,这是一个特定的拦截器。

3. AbstractUrlHandlerMapping

3.1 getHandlerInternal

从名字就可以看出它是通过url来进行匹配的。此系列大致原理是将url与对应的Handler保存在一个Map中,在getHandlerInternal方法中使用url从Map中获取Handler,AbstractUrlHandlerMapping中实现了具体用url从Map中获取Handler的过程,而Map的初始化则交给了具体的子孙类去完成。

java源码 - SpringMVC(4)之 HandlerMapping

AbstractUrlHandlerMapping重写了父类的getHandlerInternal():

	/ * *
	*查找给定请求的URL路径的处理程序。
	* @param请求当前HTTP请求
	* @返回处理程序实例,如果没有找到则{@code null}
	* /
	@Override
	@Nullable
	protected Object getHandlerInternal(HttpServletRequest request) throws Exception {
		String lookupPath = getUrlPathHelper().getLookupPathForRequest(request);
		request.setAttribute(LOOKUP_PATH, lookupPath);
		Object handler = lookupHandler(lookupPath, request);
		if (handler == null) {
			//我们需要直接关心默认处理程序,因为我们需要这样做
			//还公开它的PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE。
			Object rawHandler = null;
			if ("/".equals(lookupPath)) {
				rawHandler = getRootHandler();
			}
			if (rawHandler == null) {
				rawHandler = getDefaultHandler();
			}
			if (rawHandler != null) {
				// Bean名称还是解析的处理程序?
				if (rawHandler instanceof String) {
					String handlerName = (String) rawHandler;
					rawHandler = obtainApplicationContext().getBean(handlerName);
				}
				//可以用来校验的Handler和request是否匹配,是模板方法
				validateHandler(rawHandler, request);
				handler = buildPathExposingHandler(rawHandler, lookupPath, lookupPath, null);
			}
		}
		return handler;
	}

lookupHandler方法用于使用lookupPath从Map中查找Handler,不过很多时候并不能直接从Map中get到,因为很多Handler都是用了Pattern的匹配模式,如“/show/article/”,这里的星号可以代表任意内容而不是真正匹配url中的星号,如果Pattern中包含PathVariable也不能直接从Map中获取到。另外,一个url还可能跟多个Pattern相匹配,这时还需要选择其中最优的,所以查找过程其实并不是直接简单地从Map里获取,单独写一个方法来做也是应该的。

	/**
	*查找给定URL路径的处理程序实例。
	*
	支持直接匹配,例如已注册的"/test"匹配"/test",
	*和各种ant风格的模式匹配,例如注册的“/t*”匹配
	*“/测试”和“/团队”。有关详细信息,请参见AntPathMatcher类。
	*
	寻找最精确的模式,其中最精确的定义为
	*最长路径模式。
	@param urlPath bean映射到的URL
	* @param请求当前HTTP请求(暴露映射到的路径)
	* @返回相关的处理程序实例,如果没有找到,则返回{@code null}
	* @see # exposePathWithinMapping
	* @see org.springframework.util.AntPathMatcher
	*/
	@Nullable
	protected Object lookupHandler(String urlPath, HttpServletRequest request) throws Exception {
		// 直接匹配
		Object handler = this.handlerMap.get(urlPath);
		if (handler != null) {
			// Bean名称还是解析处理程序?
			if (handler instanceof String) {
				String handlerName = (String) handler;
				handler = obtainApplicationContext().getBean(handlerName);
			}
			validateHandler(handler, request);
			return buildPathExposingHandler(handler, urlPath, urlPath, null);
		}

		// 模式匹配 比如带*号的
		List<String> 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<String> 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名称还是解析处理程序?
			if (handler instanceof String) {
				String handlerName = (String) handler;
				handler = obtainApplicationContext().getBean(handlerName);
			}
			validateHandler(handler, request);
			String pathWithinMapping = getPathMatcher().extractPathWithinPattern(bestMatch, urlPath);

			//可能有多个“最佳模式”,让我们确保我们有正确的URI模板变量匹配他们
		
			Map<String, String> uriTemplateVariables = new LinkedHashMap<>();
			for (String matchingPattern : matchingPatterns) {
				if (patternComparator.compare(bestMatch, matchingPattern) == 0) {
					Map<String, String> vars = getPathMatcher().extractUriTemplateVariables(matchingPattern, urlPath);
					Map<String, String> 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;
	}

再来看返回方法buildPathExposingHandler:

	/ * *
	*为给定的原始处理程序构建一个处理程序对象,公开实际的
	*处理程序,{@link #PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE}以及
	*执行处理程序之前的{@link #URI_TEMPLATE_VARIABLES_ATTRIBUTE}*
	默认实现构建一个{@link HandlerExecutionChain}
	*使用一个特殊的拦截器来公开路径属性和uri模板变量
	* @param rawHandler要公开的raw处理程序
	* @param pathWithinMapping path to expose before执行处理程序
	* @param uriTemplateVariables URI模板变量,如果没有找到变量,可以是{@code null}
	* @return最终的处理程序对象
	* /
	
	protected Object buildPathExposingHandler(Object rawHandler, String bestMatchingPattern,
			String pathWithinMapping, @Nullable Map<String, String> uriTemplateVariables) {

		HandlerExecutionChain chain = new HandlerExecutionChain(rawHandler);
		chain.addInterceptor(new PathExposingHandlerInterceptor(bestMatchingPattern, pathWithinMapping));
		if (!CollectionUtils.isEmpty(uriTemplateVariables)) {
			chain.addInterceptor(new UriTemplateVariablesHandlerInterceptor(uriTemplateVariables));
		}
		return chain;
	}

在buildPathExposingHandler方法中给Handler注册两个内部拦截器PathExposingHandlerInterceptor和UriTemplateVariablesHandlerInterceptor,这两个拦截器分别在preHandle中调用了exposePathWithinMapping和exposeUriTemplateVariables方法将相应内容设置到了request的属性。

3.2 初始化

从spring容器或者子类加载handler。

	/**
	*调用{@link #detectHandlers()}方法
	*超类的初始化。
	 */
	@Override
	public void initApplicationContext() throws ApplicationContextException {
		super.initApplicationContext();
		detectHandlers();
	}
	/**
	*注册在当前ApplicationContext中找到的所有处理程序。
	处理程序的实际URL确定取决于具体情况
	* {@link #determineUrlsForHandler(String)}实现。一个豆
	*没有这样的url可以被确定,就是不被认为是一个处理程序。
	* @throws org.springframework.beans。如果处理程序不能注册,则BeansException异常
	* @see # determineUrlsForHandler(字符串)
	 */
	protected void detectHandlers() throws BeansException {

java源码 - SpringMVC(4)之 HandlerMapping

	/**
	*为给定的URL路径注册指定的处理程序。
	* @param urlPaths该bean应该映射到的url
	处理程序bean的名称
	* @抛出BeansException,如果处理程序不能被注册
	* @抛出IllegalStateException,如果注册的处理程序有冲突
	*/
	protected void registerHandler(String[] urlPaths, String beanName) throws BeansException, IllegalStateException {
		Assert.notNull(urlPaths, "URL path array must not be null");
		for (String urlPath : urlPaths) {
			registerHandler(urlPath, beanName);
		}
	}

注意:registerHandler方法并不是自己调用,也不是父类调用,而是子类调用。

	/**
	*为给定的URL路径注册指定的处理程序。
	@param urlPath bean应该映射到的URL
	处理程序实例或处理程序bean名称字符串
	* (bean名称将自动解析为相应的处理程序bean)
	* @抛出BeansException,如果处理程序不能被注册
	* @抛出IllegalStateException,如果注册的处理程序有冲突
	*/
	protected void registerHandler(String urlPath, Object handler) throws BeansException, IllegalStateException {
		Assert.notNull(urlPath, "URL path must not be null");
		Assert.notNull(handler, "Handler object must not be null");
		Object resolvedHandler = handler;

		// Eagerly resolve handler if referencing singleton via name.
		if (!this.lazyInitHandlers && handler instanceof String) {
			String handlerName = (String) handler;
			ApplicationContext applicationContext = obtainApplicationContext();
			if (applicationContext.isSingleton(handlerName)) {
				resolvedHandler = applicationContext.getBean(handlerName);
			}
		}

		Object mappedHandler = this.handlerMap.get(urlPath);
		if (mappedHandler != null) {
			if (mappedHandler != resolvedHandler) {
				throw new IllegalStateException(
						"Cannot map " + getHandlerDescription(handler) + " to URL path [" + urlPath +
						"]: There is already " + getHandlerDescription(mappedHandler) + " mapped.");
			}
		}
		else {
			if (urlPath.equals("/")) {
				if (logger.isTraceEnabled()) {
					logger.trace("Root mapping to " + getHandlerDescription(handler));
				}
				setRootHandler(resolvedHandler);
			}
			else if (urlPath.equals("/*")) {
				if (logger.isTraceEnabled()) {
					logger.trace("Default mapping to " + getHandlerDescription(handler));
				}
				setDefaultHandler(resolvedHandler);
			}
			else {
				this.handlerMap.put(urlPath, resolvedHandler);
				if (logger.isTraceEnabled()) {
					logger.trace("Mapped [" + urlPath + "] onto " + getHandlerDescription(handler));
				}
			}
		}
	}

AbstractUrlHandlerMapping里面定义了整体架构,子类只需要将Map初始化就可以了。

4. SimpleUrlHandlerMapping

SimpleUrlHandlerMapping定义了一个Map变量(自己定义一个Map主要有两个作用,第一是方便配置,第二是可以在注册前做一些预处理,如确保所有url都以“/”开头),将所有的url和Handler的对应关系放在里面,最后注册到父类的Map中;而AbstractDetectingUrlHandlerMapping则是将容器中的所有bean都拿出来,按一定规则注册到父类的Map中。

	/**
	*调用{@link #registerHandlers}方法
	*超类的初始化。
	 */
	@Override
	public void initApplicationContext() throws BeansException {
		super.initApplicationContext();
		registerHandlers(this.urlMap);
	}

registerHandlers内部又调用了Abstract-UrlHandlerMapping的registerHandler方法将我们配置的urlMap注册到AbstractUrlHandler-Mapping的Map中。

	/**
	*注册URL映射中指定的对应路径的所有处理程序。
	@param urlMap以URL路径作为键,处理程序bean或bean名称作为值的映射
	* @抛出BeansException,如果处理程序无法注册
	* @抛出IllegalStateException,如果注册的处理程序有冲突
	*/
	protected void registerHandlers(Map<String, Object> urlMap) throws BeansException {
		if (urlMap.isEmpty()) {
			logger.trace("No patterns in " + formatMappingName());
		}
		else {
			urlMap.forEach((url, handler) -> {
				//如果还没有出现,则在前加上斜杠。
				if (!url.startsWith("/")) {
					url = "/" + url;
				}
				//从处理程序bean名称中删除空格。
				if (handler instanceof String) {
					handler = ((String) handler).trim();
				}
				//调用父类的负责方法
				registerHandler(url, handler);
			});
			if (logger.isDebugEnabled()) {
				List<String> patterns = new ArrayList<>();
				if (getRootHandler() != null) {
					patterns.add("/");
				}
				if (getDefaultHandler() != null) {
					patterns.add("/**");
				}
				patterns.addAll(getHandlerMap().keySet());
				logger.debug("Patterns " + patterns + " in " + formatMappingName());
			}
		}
	}

org.springframework.web.servlet.handler.AbstractUrlHandlerMapping:
java源码 - SpringMVC(4)之 HandlerMapping

5. AbstractDetectingUrlHandlerMapping

AbstractDetectingUrlHandlerMapping也是通过重写initApplicationContext来注册Handler的,里面调用了detectHandlers方法,在detectHandlers中根据配置的detectHand-lersInAn-cestorContexts参数从Spring MVC容器或者Spring MVC及其父容器中找到所有bean的beanName,然后用determineUrlsForHandler方法对每个beanName解析出对应的urls,如果解析结果不为空则将解析出的urls和beanName(作为Handler)注册到父类的Map,注册方法依然是调用AbstractUrlHandlerMapping的registerHandler方法。
使用beanName解析urls的determineUrlsForHandler方法是模板方法,交给具体子类实现。

	/**
	*调用{@link #detectHandlers()}方法
	*超类的初始化。
	*/
	@Override
	public void initApplicationContext() throws ApplicationContextException {
		super.initApplicationContext();
		detectHandlers();
	}
	/**
	 *注册在当前ApplicationContext中找到的所有处理程序。
	处理程序的实际URL确定取决于具体情况
	* {@link #determineUrlsForHandler(String)}实现。一个豆
	*没有这样的url可以被确定,就是不被认为是一个处理程序。
	* @throws org.springframework.beans。如果处理程序不能注册,则BeansException异常
	* @see # determineUrlsForHandler(字符串)
	*/
	protected void detectHandlers() throws BeansException {
		ApplicationContext applicationContext = obtainApplicationContext();
		String[] beanNames = (this.detectHandlersInAncestorContexts ?
				BeanFactoryUtils.beanNamesForTypeIncludingAncestors(applicationContext, Object.class) :
				applicationContext.getBeanNamesForType(Object.class));

		// Take any bean name that we can determine URLs for.
		for (String beanName : beanNames) {
			String[] urls = determineUrlsForHandler(beanName);
			if (!ObjectUtils.isEmpty(urls)) {
				// 找到的URL路径:让我们把它看作一个处理程序。
				//调用父类的registerHandler
				registerHandler(urls, beanName);
			}
		}

		if ((logger.isDebugEnabled() && !getHandlerMap().isEmpty()) || logger.isTraceEnabled()) {
			logger.debug("Detected " + getHandlerMap().size() + " mappings in " + formatMappingName());
		}
	}
	/ * *
	*确定给定处理程序bean的url。
	* @param beanName候选bean的名称
	@返回为bean确定的url,如果没有,则返回空数组
	* /
	protected abstract String[] determineUrlsForHandler(String beanName);

目前它的子类只有:
java源码 - SpringMVC(4)之 HandlerMapping
BeanNameUrlHandlerMapping是检查beanName和alias是不是以“/”开头,如果是则将其作为url,里面只有一个determineUrlsForHandler方法:

public class BeanNameUrlHandlerMapping extends AbstractDetectingUrlHandlerMapping {
	/ * *
	*检查给定bean的url名称和别名,以“/”开头。
	* /
	@Override
	protected String[] determineUrlsForHandler(String beanName) {
		List<String> urls = new ArrayList<>();
		if (beanName.startsWith("/")) {
			urls.add(beanName);
		}
		String[] aliases = obtainApplicationContext().getAliases(beanName);
		for (String alias : aliases) {
			if (alias.startsWith("/")) {
				urls.add(alias);
			}
		}
		return StringUtils.toStringArray(urls);
	}
}

至此,关于HandlerMapping其实只要搞清楚,handler从哪里来,handler怎么调用,就差不多可以弄明白了。其他的基本上就是为了满足框架的可扩展性而设计使用的设计模式。

6. AbstractHandlerMethodMapping

AbstractHandlerMethodMapping直接继承自AbstractHandlerMapping。

AbstractHandlerMethodMapping系列是将Method作为Handler来使用的,这也是我们现在用得最多的一种Handler。
比如经常使用的@RequestMapping所注释的方法就是这种Handler,它专门有一个类型——HandlerMethod,也就是Method类型的Handler。

6.1 初始化

先找到MappingRegistry这个内部类:

	/ * *
	*维护所有映射到处理程序方法,暴露方法的注册表
	*执行查找和提供并发访问。
	*
	Package-private用于测试目的。
	* /
	class MappingRegistry {

本文地址:https://blog.csdn.net/littlewhitevg/article/details/107347814