上一篇博客springMVC源码分析--AbstractHandlerMapping(二)中我们介绍了AbstractHandlerMapping了,接下来我们介绍其子类AbstractUrlHandlerMapping。

在上一篇博客中我们了解到AbstractHandlerMapping提供了一个抽象类getHandlerInternal(HttpServletRequest request),我们首先看看AbstractUrlHandlerMapping中对抽象类getHandlerInternal(HttpServletRequest request)的实现。

//获取Handler,主要是通过url和method的对应关系来查找
	@Override
	protected Object getHandlerInternal(HttpServletRequest request) throws Exception {
		//获取request中的请求链接
		String lookupPath = getUrlPathHelper().getLookupPathForRequest(request);
		//根据链接查找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.
			//定义一个变量,保存找到的原始Handler
			Object rawHandler = null;
			if ("/".equals(lookupPath)) {
				rawHandler = getRootHandler();
			}
			if (rawHandler == null) {
				rawHandler = getDefaultHandler();
			}
			if (rawHandler != null) {
				// Bean name or resolved handler?
				//如果是String类型则到容器中查找具体的Bean
				if (rawHandler instanceof String) {
					String handlerName = (String) rawHandler;
					rawHandler = getApplicationContext().getBean(handlerName);
				}
				validateHandler(rawHandler, request);
				handler = buildPathExposingHandler(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;
	}

从上面的实现方法getHandlerInternal来看,首先是通过lookupHandler方法来查找Handler,这里我们看到了之前说的Map对象,用来存储url和Handler之间的关系,当Handler获取为String时需要从Bean容器中获取注入的实现类,当然在查找过程中也会有模糊匹配等查找过程。

protected Object lookupHandler(String urlPath, HttpServletRequest request) throws Exception {
		// Direct match?
		//直接从map中获取
		Object handler = this.handlerMap.get(urlPath);
		if (handler != null) {
			// Bean name or resolved handler?
			//如果是String类型则从容器中获取
			if (handler instanceof String) {
				String handlerName = (String) handler;
				handler = getApplicationContext().getBean(handlerName);
			}
			validateHandler(handler, request);
			return buildPathExposingHandler(handler, urlPath, urlPath, null);
		}
		// Pattern match?
		//通过模糊匹配来查找
		List<String> matchingPatterns = new ArrayList<String>();
		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 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);
			}
			bestPatternMatch = matchingPatterns.get(0);
		}
		if (bestPatternMatch != null) {
			handler = this.handlerMap.get(bestPatternMatch);
			if (handler == null) {
				Assert.isTrue(bestPatternMatch.endsWith("/"));
				handler = this.handlerMap.get(bestPatternMatch.substring(0, bestPatternMatch.length() - 1));
			}
			// 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 them
			Map<String, String> uriTemplateVariables = new LinkedHashMap<String, String>();
			for (String matchingPattern : matchingPatterns) {
				if (patternComparator.compare(bestPatternMatch, matchingPattern) == 0) {
					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 buildPathExposingHandler(handler, bestPatternMatch, pathWithinMapping, uriTemplateVariables);
		}
		// No handler found...
		return null;
	}

上面两个方法介绍了通过url来查找handlerMap获取handler的操作,AbstractUrlHandlerMapping中也提供了注册url和handler到handlerMap中的操作,具体的调用则要到AbstractUrlHandlerMapping的子类中实现。

//注册url和Bean的map,注册多个string的url到一个处理器中
	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);
		}
	}

	////注册url和Bean的map,将具体的Handler注入到url对应的map中
	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.
		//如果Handler是String类型而且没有设置lazyInitHandlers则从springMVC容器中获取handler
		if (!this.lazyInitHandlers && handler instanceof String) {
			String handlerName = (String) handler;
			if (getApplicationContext().isSingleton(handlerName)) {
				resolvedHandler = getApplicationContext().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.isInfoEnabled()) {
					logger.info("Root mapping to " + getHandlerDescription(handler));
				}
				setRootHandler(resolvedHandler);
			}
			else if (urlPath.equals("/*")) {
				if (logger.isInfoEnabled()) {
					logger.info("Default mapping to " + getHandlerDescription(handler));
				}
				setDefaultHandler(resolvedHandler);
			}
			else {
				this.handlerMap.put(urlPath, resolvedHandler);
				if (logger.isInfoEnabled()) {
					logger.info("Mapped URL path [" + urlPath + "] onto " + getHandlerDescription(handler));
				}
			}
		}
	}

通过上面介绍我们知道AbstractUrlHandlerMapping提供的功能就是根据url从handlerMap中获取handler和注册url和handler的对应关系到handlerMap中,当然这个过程中还包含很多其他的操作。

AbstractUrlHandlerMapping的完整源码如下:

public abstract class AbstractUrlHandlerMapping extends AbstractHandlerMapping {

	private Object rootHandler;

	private boolean useTrailingSlashMatch = false;

	private boolean lazyInitHandlers = false;

	private final Map<String, Object> handlerMap = new LinkedHashMap<String, Object>();

	public void setRootHandler(Object rootHandler) {
		this.rootHandler = rootHandler;
	}

	public Object getRootHandler() {
		return this.rootHandler;
	}

	public void setUseTrailingSlashMatch(boolean useTrailingSlashMatch) {
		this.useTrailingSlashMatch = useTrailingSlashMatch;
	}

	public boolean useTrailingSlashMatch() {
		return this.useTrailingSlashMatch;
	}

	public void setLazyInitHandlers(boolean lazyInitHandlers) {
		this.lazyInitHandlers = lazyInitHandlers;
	}

	//获取Handler,主要是通过url和method的对应关系来查找
	@Override
	protected Object getHandlerInternal(HttpServletRequest request) throws Exception {
		//获取request中的请求链接
		String lookupPath = getUrlPathHelper().getLookupPathForRequest(request);
		//根据链接查找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.
			//定义一个变量,保存找到的原始Handler
			Object rawHandler = null;
			if ("/".equals(lookupPath)) {
				rawHandler = getRootHandler();
			}
			if (rawHandler == null) {
				rawHandler = getDefaultHandler();
			}
			if (rawHandler != null) {
				// Bean name or resolved handler?
				//如果是String类型则到容器中查找具体的Bean
				if (rawHandler instanceof String) {
					String handlerName = (String) rawHandler;
					rawHandler = getApplicationContext().getBean(handlerName);
				}
				validateHandler(rawHandler, request);
				handler = buildPathExposingHandler(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;
	}

	protected Object lookupHandler(String urlPath, HttpServletRequest request) throws Exception {
		// Direct match?
		//直接从map中获取
		Object handler = this.handlerMap.get(urlPath);
		if (handler != null) {
			// Bean name or resolved handler?
			//如果是String类型则从容器中获取
			if (handler instanceof String) {
				String handlerName = (String) handler;
				handler = getApplicationContext().getBean(handlerName);
			}
			validateHandler(handler, request);
			return buildPathExposingHandler(handler, urlPath, urlPath, null);
		}
		// Pattern match?
		//通过模糊匹配来查找
		List<String> matchingPatterns = new ArrayList<String>();
		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 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);
			}
			bestPatternMatch = matchingPatterns.get(0);
		}
		if (bestPatternMatch != null) {
			handler = this.handlerMap.get(bestPatternMatch);
			if (handler == null) {
				Assert.isTrue(bestPatternMatch.endsWith("/"));
				handler = this.handlerMap.get(bestPatternMatch.substring(0, bestPatternMatch.length() - 1));
			}
			// 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 them
			Map<String, String> uriTemplateVariables = new LinkedHashMap<String, String>();
			for (String matchingPattern : matchingPatterns) {
				if (patternComparator.compare(bestPatternMatch, matchingPattern) == 0) {
					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 buildPathExposingHandler(handler, bestPatternMatch, pathWithinMapping, uriTemplateVariables);
		}
		// No handler found...
		return null;
	}

	protected void validateHandler(Object handler, HttpServletRequest request) throws Exception {
	}

	//用于给找到的Handler注册两个拦截器PathExposingHandlerInterceptor和UriTemplateVariablesHandlerInterceptor
	//这两个拦截器的的作用是将与当前url实际匹配的Pattern、匹配条件和url模板参数设置到request的属性中
	protected Object buildPathExposingHandler(Object rawHandler, String bestMatchingPattern,
			String pathWithinMapping, 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;
	}

	protected void exposePathWithinMapping(String bestMatchingPattern, String pathWithinMapping, HttpServletRequest request) {
		request.setAttribute(HandlerMapping.BEST_MATCHING_PATTERN_ATTRIBUTE, bestMatchingPattern);
		request.setAttribute(HandlerMapping.PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE, pathWithinMapping);
	}

	protected void exposeUriTemplateVariables(Map<String, String> uriTemplateVariables, HttpServletRequest request) {
		request.setAttribute(HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE, uriTemplateVariables);
	}

	//注册url和Bean的map,注册多个string的url到一个处理器中
	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);
		}
	}

	////注册url和Bean的map,将具体的Handler注入到url对应的map中
	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.
		//如果Handler是String类型而且没有设置lazyInitHandlers则从springMVC容器中获取handler
		if (!this.lazyInitHandlers && handler instanceof String) {
			String handlerName = (String) handler;
			if (getApplicationContext().isSingleton(handlerName)) {
				resolvedHandler = getApplicationContext().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.isInfoEnabled()) {
					logger.info("Root mapping to " + getHandlerDescription(handler));
				}
				setRootHandler(resolvedHandler);
			}
			else if (urlPath.equals("/*")) {
				if (logger.isInfoEnabled()) {
					logger.info("Default mapping to " + getHandlerDescription(handler));
				}
				setDefaultHandler(resolvedHandler);
			}
			else {
				this.handlerMap.put(urlPath, resolvedHandler);
				if (logger.isInfoEnabled()) {
					logger.info("Mapped URL path [" + urlPath + "] onto " + getHandlerDescription(handler));
				}
			}
		}
	}

	private String getHandlerDescription(Object handler) {
		return "handler " + (handler instanceof String ? "'" + handler + "'" : "of type [" + handler.getClass() + "]");
	}

	public final Map<String, Object> getHandlerMap() {
		return Collections.unmodifiableMap(this.handlerMap);
	}

	protected boolean supportsTypeLevelMappings() {
		return false;
	}

	private class PathExposingHandlerInterceptor extends HandlerInterceptorAdapter {

		private final String bestMatchingPattern;

		private final String pathWithinMapping;

		public PathExposingHandlerInterceptor(String bestMatchingPattern, String pathWithinMapping) {
			this.bestMatchingPattern = bestMatchingPattern;
			this.pathWithinMapping = pathWithinMapping;
		}

		@Override
		public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
			exposePathWithinMapping(this.bestMatchingPattern, this.pathWithinMapping, request);
			request.setAttribute(HandlerMapping.INTROSPECT_TYPE_LEVEL_MAPPING, supportsTypeLevelMappings());
			return true;
		}

	}

	private class UriTemplateVariablesHandlerInterceptor extends HandlerInterceptorAdapter {

		private final Map<String, String> uriTemplateVariables;

		public UriTemplateVariablesHandlerInterceptor(Map<String, String> uriTemplateVariables) {
			this.uriTemplateVariables = uriTemplateVariables;
		}

		@Override
		public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
			exposeUriTemplateVariables(this.uriTemplateVariables, request);
			return true;
		}
	}

}

springMVC源码分析--AbstractUrlHandlerMapping(三)的更多相关文章

  1. springmvc 源码分析(三) -- 自定义处理器映射器和自定义处理器适配器,以及自定义参数解析器 和错误跳转自定页面

    测试环境搭建: 本次搭建是基于springboot来实现的,代码在码云的链接:https://gitee.com/yangxioahui/thymeleaf.git DispatcherServlet ...

  2. springMVC源码分析--AbstractDetectingUrlHandlerMapping(五)

    上一篇博客springMVC源码分析--AbstractUrlHandlerMapping(三)中我们介绍了AbstractUrlHandlerMapping,主要介绍了一个handlerMap的ur ...

  3. springMVC源码分析--SimpleUrlHandlerMapping(四)

    上一篇博客springMVC源码分析--AbstractUrlHandlerMapping(三)中我们介绍了AbstractUrlHandlerMapping,主要介绍了一个handlerMap的ur ...

  4. Spring MVC源码分析(三):SpringMVC的HandlerMapping和HandlerAdapter的体系结构设计与实现

    概述在我的上一篇文章:Spring源码分析(三):DispatcherServlet的设计与实现中提到,DispatcherServlet在接收到客户端请求时,会遍历DispatcherServlet ...

  5. springMVC源码分析--ViewNameMethodReturnValueHandler返回值处理器(三)

    之前两篇博客springMVC源码分析--HandlerMethodReturnValueHandler返回值解析器(一)和springMVC源码分析--HandlerMethodReturnValu ...

  6. springMVC源码分析--RequestParamMethodArgumentResolver参数解析器(三)

    之前两篇博客springMVC源码分析--HandlerMethodArgumentResolver参数解析器(一)和springMVC源码解析--HandlerMethodArgumentResol ...

  7. springMVC源码分析--SimpleControllerHandlerAdapter(三)

    上一篇博客springMVC源码分析--HandlerAdapter(一)中我们主要介绍了一下HandlerAdapter接口相关的内容,实现类及其在DispatcherServlet中执行的顺序,接 ...

  8. springMVC源码分析--拦截器HandlerExecutionChain(三)

    上一篇博客springMVC源码分析--HandlerInterceptor拦截器调用过程(二)中我们介绍了HandlerInterceptor的执行调用地方,最终HandlerInterceptor ...

  9. SpringMVC源码分析--容器初始化(三)HttpServletBean

    在上一篇博客springMVC源码分析--容器初始化(二)DispatcherServlet中,我们队SpringMVC整体生命周期有一个简单的说明,并没有进行详细的源码分析,接下来我们会根据博客中提 ...

随机推荐

  1. SQL SERVER之查询外键及索引

    --查询表或数据库中的所有外键 select A.name as 约束名, object_name(b.parent_object_id) as 外健表, c.name as 外键列, object_ ...

  2. 音频压缩编码 opus 附完整C++代码示例

    绝大数人都知道mp3格式编码,以及aac,amr等压缩格式编码. 而在语音通信界有一个强悍的音频格式编码opus. 经过实测,压缩比最高可以达到1:10. 100KB 压缩后 10KB 虽然是有损压缩 ...

  3. 常用linux命令备忘

    备忘: 关闭防火墙:# systemctl stop firewalld 查看防火墙状态:#  systemctl status firewalld 停止防火墙:#  systemctl disabl ...

  4. BZOJ 3817 Sum

    Description 给定正整数N,R.求 Input 第一行一个数 T,表示有 T 组测试数据. 接下来 T 行,每行两个正整数 n,r. Output 输出 T 行,每行一个整数表示答案. Sa ...

  5. [HEOI2015]小Z的房间

    Description 你突然有了一个大房子,房子里面有一些房间.事实上,你的房子可以看做是一个包含n*m个格子的格状矩形,每个格子是一个房间或者是一个柱子.在一开始的时候,相邻的格子之间都有墙隔着. ...

  6. hdu5586 BestCoder Round #64 (div.2)

    问题描述 给n个数{A}_{1},{A}_{2}....{A}_{n}A​1​​,A​2​​....A​n​​,你可以选择一个区间(也可以不选),区间里每个数x变成f(x),其中f(x)=(1890x ...

  7. Android 自定义支持快速搜索筛选的选择控件(一)

    Android 自定义支持快速搜索筛选的选择控件 项目中遇到选择控件选项过多,需要快速查找匹配的情况. 做了简单的Demo,效果图如下: 源码地址:https://github.com/whieenz ...

  8. .net4.0设计模式(一)使用Lazy的单例模式

    延迟加载,亦称延迟实例化,延迟初始化等, 主要表达的思想是,把对象的创建将会延迟到使用时创建,而不是在对象实例化时创建对象,即用时才加载.这种方式有助于提高于应用程序的性能,避免浪费计算,节省内存的使 ...

  9. Spring中<context:annotation-config/>

    最近在研究Spring中<context:annotation-config/>配置的作用,现记录如下: <context:annotation-config/>的作用是向Sp ...

  10. 配置文件错误导致jenkins无法启动 org.xmlpull.v1.XmlPullParserException: only 1.0 is supported as <?xml version not '1.1' (position: START_DOCUMENT seen <?xml version=\'1.1\'... @1:19)

    org.xmlpull.v1.XmlPullParserException: only 1.0 is supported as <?xml version not '1.1' (position ...