SpringMVC处理HTTP分发请求

HandlerMapping的配置和设计原理

在初始化完成时,在上下文环境中已定义的所有的HandlerMapping都已经被加载了,这些加载的handlerMapping被放在一个List中并被排序,存储着HTTP请求对应的映射数据。这个List中的每一个元素都对应着一个具体的handlerMapping的配置,一般每一个handlerMapping可以持有一系列从URL请求道Controller的映射,而Spring MVC提供了一系列的HandlerMapping实现。


以SimpleUrlHandlerMapping这个handlerMapping为例来分析HandlerMapping的设计与实现。在SimpleUrlHandlerMapping中,定义了一个map来持有一系列的映射关系。通过这些在HandlerMapping中定义的映射关系,即这些URL请求和控制器的对应关系,使Spring MVC应用可以根据HTTP请求确定一个对应的Controller。具体来说,这些映射关系是确定接口类HandlerMapping来封装的,在HandlerMapping接口中定义了一个getHandler方法,通过这个方法,可以获得与HTTP请求对应的HandlerExecutionChain,在这个HandlerExecutionChain中,封装了具体的Controller对象,如下代码:

public interface HandlerMapping {

	/**
	 * Name of the {@link HttpServletRequest} attribute that contains the path
	 * within the handler mapping, in case of a pattern match, or the full
	 * relevant URI (typically within the DispatcherServlet's mapping) else.
	 * <p>Note: This attribute is not required to be supported by all
	 * HandlerMapping implementations. URL-based HandlerMappings will
	 * typically support it, but handlers should not necessarily expect
	 * this request attribute to be present in all scenarios.
	 */
	String PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE = HandlerMapping.class.getName() + ".pathWithinHandlerMapping";

	/**
	 * Name of the {@link HttpServletRequest} attribute that contains the URI
	 * templates map, mapping variable names to values.
	 * <p>Note: This attribute is not required to be supported by all
	 * HandlerMapping implementations. URL-based HandlerMappings will
	 * typically support it, but handlers should not necessarily expect
	 * this request attribute to be present in all scenarios.
	 */
	String URI_TEMPLATE_VARIABLES_ATTRIBUTE = HandlerMapping.class.getName() + ".uriTemplateVariables";

	/**
	 * Return a handler and any interceptors for this request. The choice may be made
	 * on request URL, session state, or any factor the implementing class chooses.
	 * <p>The returned HandlerExecutionChain contains a handler Object, rather than
	 * even a tag interface, so that handlers are not constrained in any way.
	 * For example, a HandlerAdapter could be written to allow another framework's
	 * handler objects to be used.
	 * <p>Returns {@code null} if no match was found. This is not an error.
	 * The DispatcherServlet will query all registered HandlerMapping beans to find
	 * a match, and only decide there is an error if none can find a handler.
	 * @param request current HTTP request
	 * @return a HandlerExecutionChain instance containing handler object and
	 * any interceptors, or {@code null} if no mapping found
	 * @throws Exception if there is an internal error
	 */
	/*
	 * 调用getHandler实际上返回的是一个HandlerExecutionChain,这是典型的Command的模式的使用,
	 * 这个HandlerExecutionChain不但持有handler本身,还包括了处理这个HTTP请求相关的拦截器
	 */
	HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception;

}

这个HandlerExecutionChain,它持有一个Interceptor链和一个handler对象,这个handler对象实际上就是HTTP请求对应的Controller,在持有这个handler对象的同时,还在HandlerExecutionChain中设置了一个拦截器链,通过这个拦截器链和handler都进行配置,这些配置都是在HandlerExecutionChain的初始化函数中完成的。为了维护这个拦截器链和handler,HandlerExecutionChain还提供了一系列与拦截器链维护相关的一些操作,如可以为拦截器链增加拦截器的addInterceptor方法等。HandlerExecutionChain的实现如下:

public class HandlerExecutionChain {

	private static final Log logger = LogFactory.getLog(HandlerExecutionChain.class);

	private final Object handler;

	private HandlerInterceptor[] interceptors;

	private List<HandlerInterceptor> interceptorList;

	private int interceptorIndex = -1;

	/**
	 * Create a new HandlerExecutionChain.
	 * @param handler the handler object to execute
	 */
	public HandlerExecutionChain(Object handler) {
		this(handler, null);
	}

	/**
	 * Create a new HandlerExecutionChain.
	 * @param handler the handler object to execute
	 * @param interceptors the array of interceptors to apply
	 * (in the given order) before the handler itself executes
	 */
	public HandlerExecutionChain(Object handler, HandlerInterceptor[] interceptors) {
		if (handler instanceof HandlerExecutionChain) {
			HandlerExecutionChain originalChain = (HandlerExecutionChain) handler;
			this.handler = originalChain.getHandler();
			this.interceptorList = new ArrayList<HandlerInterceptor>();
			CollectionUtils.mergeArrayIntoCollection(originalChain.getInterceptors(), this.interceptorList);
			CollectionUtils.mergeArrayIntoCollection(interceptors, this.interceptorList);
		}
		else {
			this.handler = handler;
			this.interceptors = interceptors;
		}
	}

	/**
	 * Return the handler object to execute.
	 * @return the handler object
	 */
	public Object getHandler() {
		return this.handler;
	}

	public void addInterceptor(HandlerInterceptor interceptor) {
		initInterceptorList();
		this.interceptorList.add(interceptor);
	}

	public void addInterceptors(HandlerInterceptor[] interceptors) {
		if (interceptors != null) {
			initInterceptorList();
			this.interceptorList.addAll(Arrays.asList(interceptors));
		}
	}

	private void initInterceptorList() {
		if (this.interceptorList == null) {
			this.interceptorList = new ArrayList<HandlerInterceptor>();
		}
		if (this.interceptors != null) {
			this.interceptorList.addAll(Arrays.asList(this.interceptors));
			this.interceptors = null;
		}
	}

	/**
	 * Return the array of interceptors to apply (in the given order).
	 * @return the array of HandlerInterceptors instances (may be {@code null})
	 */
	public HandlerInterceptor[] getInterceptors() {
		if (this.interceptors == null && this.interceptorList != null) {
			this.interceptors = this.interceptorList.toArray(new HandlerInterceptor[this.interceptorList.size()]);
		}
		return this.interceptors;
	}

}

HandlerExecutionChain中定义的Handler和Interceptor需要在定义HandlerMapping时配置好,例如对具体的SimpleURLHandlerMapping,要做的就是根据URL映射的方式,注册Handler和Interceptor,从而维护一个反映这种映射关系的handlerMap。当需要匹配HTTP请求时,需要查询这个handlerMap中的信息来得到对应的HandlerExecutionChain。这些信息是什么时候配置好的呢?这里有一个注册过程,这个注册过程在容器对Bean进行依赖注入时发生,它实际上是通过一个Bean的postProcessor来完成的。

了解了这些调用关系的发生后,我们将进一步分析在SimpleUrlHandlerMapping中的注册过程是如何完成的,如下代码:

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

protected void registerHandlers(Map<String, Object> urlMap) throws BeansException {
	if (urlMap.isEmpty()) {
		logger.warn("Neither 'urlMap' nor 'mappings' set on SimpleUrlHandlerMapping");
	}
	else {
		// 这里对Bean的配置进行解析,然后调用基类的registerHandler完成注册
		for (Map.Entry<String, Object> entry : urlMap.entrySet()) {
			String url = entry.getKey();
			Object handler = entry.getValue();
			// Prepend with slash if not already present.
			if (!url.startsWith("/")) {
				url = "/" + url;
			}
			// Remove whitespace from handler bean name.
			if (handler instanceof String) {
				handler = ((String) handler).trim();
			}
			registerHandler(url, handler);
		}
	}
}

这个SimpleUrlHandlerMapping注册过程的完成,很大一部分需要它的基类来配合,这个基类就是AbstractUrlHandlerMapping。AbstractUrlHandlerMapping中的处理如下代码。在这个处理过程中,如果使用Bean的名称作为映射,那么直接从容器中获取这个HTTP映射对应的Bean,然后还要对不同的URL配置进行解析处理,比如在HTTP请求中配置成”/“和通配符”/*“的URL,以及正常的URL请求,完成这个解析处理过程以后,会把URL和handler作为键值对放到一个handlerMap中去。

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.
	// 如果直接用bean名称进行映射,那就直接从容器中获取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 { // 处理URL是“/”的映射,把这个“/”映射的controller设置到rootHandler中
		if (urlPath.equals("/")) {
			if (logger.isInfoEnabled()) {
				logger.info("Root mapping to " + getHandlerDescription(handler));
			}
			setRootHandler(resolvedHandler);
		}
		// 处理URL是“/*”的映射,把这个“/”映射的Controller设置到defaultHandler中
		else if (urlPath.equals("/*")) {
			if (logger.isInfoEnabled()) {
				logger.info("Default mapping to " + getHandlerDescription(handler));
			}
			setDefaultHandler(resolvedHandler);
		}
		// 处理正常的URL映射,设置handlerMap的key和value,分别对应于URL和映射的controller
		else {
			this.handlerMap.put(urlPath, resolvedHandler);
			if (logger.isInfoEnabled()) {
				logger.info("Mapped URL path [" + urlPath + "] onto " + getHandlerDescription(handler));
			}
		}
	}
}

这里的handlerMap是一个HashMap,其中保存了URL请求和Controller的映射关系,这个handlerMap是在AbstractUrlHandlerMapping中定义的,如下所示:

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

这个配置好URL请求和handler映射数据的handlerMap,为Spring MVC响应HTTP请求准备好了基本的映射数据,根据这个handlerMap以及设置于其中的映射数据,可以方便地由URL请求得到它所对应的handler。有了这些准备工作,Spring MVC姐可以静静等待HTTP请求的到来了。

使用HandlerMapping完成请求的映射处理

通过SimpleUrlHandlerMapping的实现来分析HandlerMapping的接口方法getHandler,该方法会根据初始化时得到的映射关系来生成DispatcherServlet需要的HandlerExecutionChain,也就是说,这个getHandler方法是实际使用HandlerMapping完成请求的映射处理的地方。在前面的HandlerExecutionChain的执行过程中,首先在AbstractHandlerMapping中启动了getHandler的调用,如下代码:

public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
	Object handler = getHandlerInternal(request);
	// 使用默认的Handler,也就是“/”对应的handler
	if (handler == null) {
		handler = getDefaultHandler();
	}
	if (handler == null) {
		return null;
	}
	// Bean name or resolved handler?
	// 这里通过名称取出对应的Handler Bean
	if (handler instanceof String) {
		String handlerName = (String) handler;
		handler = getApplicationContext().getBean(handlerName);
	}
	// 这里把Handler封装到HandlerExecutionChain中并加上拦截器
	return getHandlerExecutionChain(handler, request);
}

/**
 * Build a {@link HandlerExecutionChain} for the given handler, including
 * applicable interceptors.
 * <p>The default implementation builds a standard {@link HandlerExecutionChain}
 * with the given handler, the handler mapping's common interceptors, and any
 * {@link MappedInterceptor}s matching to the current request URL. Subclasses
 * may override this in order to extend/rearrange the list of interceptors.
 * <p><b>NOTE:</b> The passed-in handler object may be a raw handler or a
 * pre-built {@link HandlerExecutionChain}. This method should handle those
 * two cases explicitly, either building a new {@link HandlerExecutionChain}
 * or extending the existing chain.
 * <p>For simply adding an interceptor in a custom subclass, consider calling
 * {@code super.getHandlerExecutionChain(handler, request)} and invoking
 * {@link HandlerExecutionChain#addInterceptor} on the returned chain object.
 * @param handler the resolved handler instance (never {@code null})
 * @param request current HTTP request
 * @return the HandlerExecutionChain (never {@code null})
 * @see #getAdaptedInterceptors()
 */
protected HandlerExecutionChain getHandlerExecutionChain(Object handler, HttpServletRequest request) {
	HandlerExecutionChain chain = (handler instanceof HandlerExecutionChain ?
			(HandlerExecutionChain) handler : new HandlerExecutionChain(handler));
	chain.addInterceptors(getAdaptedInterceptors());

	String lookupPath = this.urlPathHelper.getLookupPathForRequest(request);
	for (MappedInterceptor mappedInterceptor : this.mappedInterceptors) {
		if (mappedInterceptor.matches(lookupPath, this.pathMatcher)) {
			chain.addInterceptor(mappedInterceptor.getInterceptor());
		}
	}

	return chain;
}

取得handler的具体过程在getHandlerInternal方法中实现,这个方法接受HTTP请求作为参数,它的实现在AbstractHandlerMapping的子类AbstractUrlHandlerMapping中,这个实现过程包括从HTTP请求中得到URL,并根据URL到urlMapping中获得handler,过程如下:

protected Object getHandlerInternal(HttpServletRequest request) throws Exception {
	// 从request中得到请求的URL路径
	String lookupPath = getUrlPathHelper().getLookupPathForRequest(request);
	/* 将得到的URL路径与Handler进行匹配,得到对应的Handlerm,如果没有对应的Handler,返回null
	 * 这样默认的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?
			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;
}

/**
 * Look up a handler instance for the given URL path.
 * <p>Supports direct matches, e.g. a registered "/test" matches "/test",
 * and various Ant-style pattern matches, e.g. a registered "/t*" matches
 * both "/test" and "/team". For details, see the AntPathMatcher class.
 * <p>Looks for the most exact pattern, where most exact is defined as
 * the longest path pattern.
 * @param urlPath URL the bean is mapped to
 * @param request current HTTP request (to expose the path within the mapping to)
 * @return the associated handler instance, or {@code null} if not found
 * @see #exposePathWithinMapping
 * @see org.springframework.util.AntPathMatcher
 */
// lookupHandler根据URL路径启动在handlerMap中对handler的检索,并最终返回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 = 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);
		}
	}
	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);
		// 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;
}

经过这一系列对HTTP请求进行解析和匹配handler的过程,得到了与请求对应的handler处理器。再返回的handler中,已经完成了在HandlerExecutionChain中的封装工作,为handler对HTTP请求的响应最好了准备。然而,在MVC中,还有一个重要的问题:请求是怎样实现分发,从而到达对应的handler的呢?有了前面的分析,如果再对前端HTTP请求分发的过程有所了解,那么基本上可以看到HTTP请求在MVC框架中处理过程的全貌了。

Spring MVC对HTTP请求的分发处理

我们需要看一下DispatcherServlet,毫无疑问,它是Spring MVC框架中非常重要的一个类,不但建立了自己持有的IoC容器,还肩负着请求分发处理的重任。在MVC框架初始化完成以后。,对HTTP请求的处理是在doService()方法中完成的。DispatcherServlet是HttpServlet的子类,与其他的HttpServlet一样,可以通过doService()来响应HTTP请求。然而,依照Spring MVC的使用,业务逻辑的调用入口是在handler的handler函数中实现的,这里是连接Spring MVC和应用业务逻辑实现的地方。DispatcherServlcet的doService的实现如下代码:

protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {
	if (logger.isDebugEnabled()) {
		String resumed = WebAsyncUtils.getAsyncManager(request).hasConcurrentResult() ? " resumed" : "";
		logger.debug("DispatcherServlet with name '" + getServletName() + "'" + resumed +
				" processing " + request.getMethod() + " request for [" + getRequestUri(request) + "]");
	}

	// Keep a snapshot of the request attributes in case of an include,
	// to be able to restore the original attributes after the include.
	Map<String, Object> attributesSnapshot = null;
	if (WebUtils.isIncludeRequest(request)) {
		attributesSnapshot = new HashMap<String, Object>();
		Enumeration<?> attrNames = request.getAttributeNames();
		while (attrNames.hasMoreElements()) {
			String attrName = (String) attrNames.nextElement();
			if (this.cleanupAfterInclude || attrName.startsWith("org.springframework.web.servlet")) {
				attributesSnapshot.put(attrName, request.getAttribute(attrName));
			}
		}
	}

	// Make framework objects available to handlers and view objects.
	// 对HTTP请求参数进行快照处理
	request.setAttribute(WEB_APPLICATION_CONTEXT_ATTRIBUTE, getWebApplicationContext());
	request.setAttribute(LOCALE_RESOLVER_ATTRIBUTE, this.localeResolver);
	request.setAttribute(THEME_RESOLVER_ATTRIBUTE, this.themeResolver);
	request.setAttribute(THEME_SOURCE_ATTRIBUTE, getThemeSource());

	FlashMap inputFlashMap = this.flashMapManager.retrieveAndUpdate(request, response);
	if (inputFlashMap != null) {
		request.setAttribute(INPUT_FLASH_MAP_ATTRIBUTE, Collections.unmodifiableMap(inputFlashMap));
	}
	request.setAttribute(OUTPUT_FLASH_MAP_ATTRIBUTE, new FlashMap());
	request.setAttribute(FLASH_MAP_MANAGER_ATTRIBUTE, this.flashMapManager);

	try {
		// 这个doDispatch是分发请求的入口
		doDispatch(request, response);
	}
	finally {
		if (WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) {
			return;
		}
		// Restore the original attribute snapshot, in case of an include.
		if (attributesSnapshot != null) {
			restoreAttributesAfterInclude(request, attributesSnapshot);
		}
	}
}

对请求的处理实际上是由doDispatch()来完成的,如下代码所示。这个doDispatch方法是DispatcherServlet完成Dispatcher的主要方法,包括准备ModelAndView,调用getHandler来响应HTTP请求,然后通过执行Handler的处理来得到返回的ModelAndView结果,最后把这个ModelAndView对象交给相应的视图对象去呈现。

protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
	HttpServletRequest processedRequest = request;
	HandlerExecutionChain mappedHandler = null;
	boolean multipartRequestParsed = false;

	WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);

	// 这里为试图准备好一个ModelAndView,这个ModelAndView持有handler处理请求的的结果
	try {
		ModelAndView mv = null;
		Exception dispatchException = null;

		try {
			processedRequest = checkMultipart(request);
			multipartRequestParsed = (processedRequest != request);

			// Determine handler for the current request.
			// 根据请求得到对应的handler,handler的注册以及getHandler的实现
			mappedHandler = getHandler(processedRequest);
			if (mappedHandler == null || mappedHandler.getHandler() == null) {
				noHandlerFound(processedRequest, response);
				return;
			}

			// Determine handler adapter for the current request.
			// 这里是实际调用handler的地方,在执行handler之前,用HandlerAdapter先检查
			// 一下handler的合法性,是不是按Spring的要求编写的handler
			// handler处理的结果封装到ModelAndView对象中,为视图提供展现数据
			HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());

			// Process last-modified header, if supported by the handler.
			String method = request.getMethod();
			boolean isGet = "GET".equals(method);
			if (isGet || "HEAD".equals(method)) {
				long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
				if (logger.isDebugEnabled()) {
					logger.debug("Last-Modified value for [" + getRequestUri(request) + "] is: " + lastModified);
				}
				if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
					return;
				}
			}

			if (!mappedHandler.applyPreHandle(processedRequest, response)) {
				return;
			}

			try {
				// Actually invoke the handler.
				/*
				 * 通过调用HandleAdapter的handle方法,实际上触发对Controller的
				 * handleRequest方法的调用
				 */
				mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
			}
			finally {
				if (asyncManager.isConcurrentHandlingStarted()) {
					return;
				}
			}

			applyDefaultViewName(request, mv);
			mappedHandler.applyPostHandle(processedRequest, response, mv);
		}
		catch (Exception ex) {
			dispatchException = ex;
		}
		processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
	}
	catch (Exception ex) {
		triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
	}
	catch (Error err) {
		triggerAfterCompletionWithError(processedRequest, response, mappedHandler, err);
	}
	finally {
		if (asyncManager.isConcurrentHandlingStarted()) {
			// Instead of postHandle and afterCompletion
			mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
			return;
		}
		// Clean up any resources used by a multipart request.
		if (multipartRequestParsed) {
			cleanupMultipart(processedRequest);
		}
	}
}

我们可以看到和MVC框架紧密相关的代码,比如如何得到和HTTP请求相对应的HandlerExecutionChain,执行handler并把模型数据展现到视图中。这个handler的请求处理过程是一个比较典型的Command模式的应用。在DispatcherServlet中取得handler的过程如下:

protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
	// 这里是从HandlerMapping中去取handler的调用,与前面对handlerMapping的分析在这里就接上了
	for (HandlerMapping hm : this.handlerMappings) {
		if (logger.isTraceEnabled()) {
			logger.trace(
					"Testing handler map [" + hm + "] in DispatcherServlet with name '" + getServletName() + "'");
		}
		HandlerExecutionChain handler = hm.getHandler(request);
		if (handler != null) {
			return handler;
		}
	}
	return null;
}

可以看到,通过在DispatcherServlet中持有的handlerMapping来生成一个。handlerMapping得到handler的过程会遍历当前持有的所有handlerMapping,因为在DispatcherServlet中可能定义了不止一个handlerMapping。在这一系列的handlerMapping中,只要找到一个需要的handler,就会停止查找,而返回当前已经得到的handler。在找到handler以后,通过handler返回的是一个HandlerExecutionChain对象,其中包含了最终的Controller和定义的一个拦截器链。对于这个过程,在前面对SimpleUrlHandlerMapping的实现中已经分析过了,在那里了解了getHandler是怎样得到一个HandlerExecutionChain的。得到HandlerExecutionChain以后,DispatcherServlet通过HandlerAdapter对这个Handler的合法性进行判断,然后返回适配结果。这个处理代码如下:

protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
	// 对持有的所有adapter进行匹配
	for (HandlerAdapter ha : this.handlerAdapters) {
		if (logger.isTraceEnabled()) {
			logger.trace("Testing handler adapter [" + ha + "]");
		}
		if (ha.supports(handler)) {
			return ha;
		}
	}
	throw new ServletException("No adapter for handler [" + handler +
			"]: The DispatcherServlet configuration needs to include a HandlerAdapter that supports this handler");
}

通过判断,可以知道这个handler是不是Controller接口的实现,比如可以通过具体HandlerAdapter实现来了解这个适配过程。以SimpleControllerHandlerAdapter的实现为例来了解这个判断是怎样起作用的,如下代码所示。这个判断通过support方法来实现,判断当前的handler是不是Controller对象,如果是,那么返回true,如果不是,那么返回false。

public class SimpleControllerHandlerAdapter implements HandlerAdapter {

	@Override
	// 判断将要调用的handler是不是Controller
	public boolean supports(Object handler) {
		return (handler instanceof Controller);
	}

	@Override
	public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
			throws Exception {

		return ((Controller) handler).handleRequest(request, response);
	}

	@Override
	public long getLastModified(HttpServletRequest request, Object handler) {
		if (handler instanceof LastModified) {
			return ((LastModified) handler).getLastModified(request);
		}
		return -1L;
	}

}

经过上面一系列的处理,得到了handler对象,接着就可以开始调用handler对象中的HTTP响应了。在handler中封装了应用业务逻辑,由这些逻辑对HTTP请求进行相应的处理,生成各种需要的数据,并把这些数据封装到ModelAndView对象中去,这个ModelAndView的数据封装是Spirng MVC框架的要求。对handler来说,这些都是通过调用handler的handleRequest方法来触发完成的。在得到ModelAndView对象以后,这个ModelAndView对象会被交给MVC模式中的视图类,由视图类对ModelAndView对象中的数据进行呈现。视图呈现的调用入口在DispatcherServlet的doDispatcher方法中实现,它的调用入口是render方法。

猜你喜欢

转载自blog.csdn.net/qq_32998153/article/details/80326850