Spring MVC与Web环境(三):HandlerMapping的配置以及处理请求

在上一篇的博客中,我提到了关于HandlerMapping的作用。在原书中作者是这样定义它的。每一个HandlerMapping可以持有一系列从URL请求到Controller的映射。在每一个HandlerMapping中都定义了一个map来持有这一系列的映射关系。在这个方法的定义中,通过解析request请求获取其中请求的URL路径,然后找到对应的handler对象,将这个对象封装到HandlerExecutionChain中进行返回。

1.HandlerMapping的配置以及HandlerExecutionChain的实现

首先来看HandlerExecutionChain这个类

	private final Object handler;

	private HandlerInterceptor[] interceptors;

	private List<HandlerInterceptor> interceptorList;

这个里面定义了handler也就是HTTP请求对应的Controller对象以及一系列的拦截器。还提供了一系列和拦截器有关的维护工作。

例如这里面的addInterceptor(HandlerInterceptor)方法等等。

这个里面定义的Handler和Interceptor需要在定义HandlerMapping时配置好。在SimpleUrlHandlerMapping类中就有一个urlMap来实现匹配HTTP请求。

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

那么这个urlMap是在什么时候进行配置的呢?

来看这两个方法

public void setMappings(Properties mappings) {
		CollectionUtils.mergePropertiesIntoMap(mappings, this.urlMap);
	}

 

public void setUrlMap(Map<String, ?> urlMap) {
		this.urlMap.putAll(urlMap);
	}

之后就是将对应的信息注册到Handler

public void initApplicationContext() throws BeansException {
		super.initApplicationContext();
		registerHandlers(this.urlMap);
	}

首先是对容器的回调,调用包含有handler对象的容器。接着就是将这些handler注册到urlMap中。

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

这个方法里面涉及到了对url映射的处理。包括对"/" 和 "/*”的处理

在SimpleUrlHandlerMapping的父类AbstractUrlHandlerMapping中维护了一个

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

这个handlerMap对象配置完毕后,就已经为Spring MVC响应HTTP请求准备好了基本的映射数据。

2.使用HandlerMapping完成请求的映射过程

具体的请求处理是是由getHandler方法来实现的。该方法会根据在设置好的handlerMap来返回相应的请求。

在AbstractHandlerMapping类中实现了这个方法。

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 = getApplicationContext().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;
	}

这个方法将取得handler对象和拦截器结合在一起

	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) {
			if (interceptor instanceof MappedInterceptor) {
				MappedInterceptor mappedInterceptor = (MappedInterceptor) interceptor;
				if (mappedInterceptor.matches(lookupPath, this.pathMatcher)) {
					chain.addInterceptor(mappedInterceptor.getInterceptor());
				}
			}
			else {
				chain.addInterceptor(interceptor);
			}
		}
		return chain;
	}

具体的获取handler对象是在getHandlerExecutionChain中完成的

首先从request中得到请求的URL路径

String lookupPath = getUrlPathHelper().getLookupPathForRequest(request);

之后根据这个lookupHandler在handlerMap中对handler进行检索并返回

Object handler = lookupHandler(lookupPath, request);

经过这一系列对Http请求进行解析和匹配的过程,得到了与请求对应的handler处理器。但是Spring MVC如何将HTTP请求对应到相应的handler我们还不了解。这中间还要进行一些准备工作。

下一篇博客我将讲述请求如何实现分发,从而到达对应的handler。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值