上一篇文章我们已经讨论过了DispatcherServlet类的初始化问题,本篇博客则就SpringMVC处理一次完整的请求进行讨论。

1. 继承链

首先让我们再来看看继承链

ansible 字符串匹配 ansible实现截取字符串_源码

由继承图来看: ServletServletConfig功能被合并在一个类中。但又通过不同的接口进行功能分离

2. doDispatch方法

作为DispatcherServlet类中的核心实现,也是SpringMVC的调度中心,这个方法直接好好研读。

// DispatcherServlet.doDispatch
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
	HttpServletRequest processedRequest = request;
	// HandlerExecutionChain, 典型的职责链模式
	//  在springMVC里非常常见,例如4.1新增的接口ResourceResolverChain。
	HandlerExecutionChain mappedHandler = null;
	boolean multipartRequestParsed = false;

	WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);

	try {
		ModelAndView mv = null;
		Exception dispatchException = null;

		try {
			// 默认情况下 this.multipartResolver 为null;
			// Convert the request into a multipart request, and make multipart resolver available.
			processedRequest = checkMultipart(request);
			multipartRequestParsed = (processedRequest != request);

			// Determine handler for the current request.
			// 筛选出处理当前request的handler(HandlerExecutionChain类型的)
			mappedHandler = getHandler(processedRequest);
			if (mappedHandler == null || mappedHandler.getHandler() == null) {
				// 处理没有匹配项的情况
				noHandlerFound(processedRequest, response);
				return;
			}

			// Determine handler adapter for the current request.
			// 根据当前的handler找到对应的HandlerAdapter, 对当前Handler进行适配, 而不是直接拿来就进行处理。
			// 	1. 这里的适配是对我们Object类型的Handler进行适配;
			//  2. 而上面返回的HandlerExecutionChain 类型也是围绕该Object类型的Handler进行封装的一个Chain.
			//  3. 再强调下该handler是个Object类型,这几乎是给与了无尚的灵活性。
			// 这里的技巧是将权限下方给每个HandlerAdapter, 由HandlerAdapter决定是否适配这个Handler(注意这个方法参数handler是Object类型)
			// 对于我们使用@RequestMapping注解的方法,这里的ha是RequestMappingHandlerAdapter类型
			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;
				}
			}
			// 拦截器的前置处理,若某个拦截器返回false,直接结束本次请求的处理
			if (!mappedHandler.applyPreHandle(processedRequest, response)) {
				return;
			}

			// Actually invoke the handler.
			// 调用真正的handler,即调用用户逻辑; 返回ModelAndView
			//  对于本次示例, 这里返回的是null
			mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

			if (asyncManager.isConcurrentHandlingStarted()) {
				return;
			}

			// 对于本次示例, 这里直接是空执行
			applyDefaultViewName(request, mv);
			// 拦截器的后置处理。
			// 默认拦截器有三个,其对applyPostHandle的实现都是空处理。
			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) {
		// 触发Error完成事件
		triggerAfterCompletionWithError(processedRequest, response, mappedHandler, err);
	}
	finally {
		if (asyncManager.isConcurrentHandlingStarted()) {
			// Instead of postHandle and afterCompletion
			if (mappedHandler != null) {
				mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
			}
		}
		else {
			// Clean up any resources used by a multipart request.
			if (multipartRequestParsed) {
				cleanupMultipart(processedRequest);
			}
		}
	}
}
2.1 关于handler

先分析下这两行代码

HandlerExecutionChain  mappedHandler = getHandler(processedRequest);

HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
  1. 其中HandlerExecutionChain类就是围绕该Object类型的handler进行封装的一个Chain。
  2. HandlerAdapter接口也是针对该Object类型的handler进行的适配 。
  3. 该handler又是个Object类型,所以这几乎是预留了无上的灵活性

然后我们来具体分析 getHandlergetHandlerAdapter方法

2.2 getHandler方法
// DispatcherServlet类定义的getHandler方法
protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
	// 在handlerMappings的顺序,可以通过实现Order接口来设置
	// 这是因为在 initHandlerMappings 方法中,会使用AnnotationAwareOrderComparator 类对找到的 HandlerMapping集合进行排序(详细请参见本人的上一篇博客, 或者直接查阅相应源码)
	// 关于HandlerMapping接口,可以参见下面的专门讲解
	for (HandlerMapping hm : this.handlerMappings) {
		// 这里的精妙就在于HandlerMapping接口唯一定义的getHandler方法; 更详尽的参见下面的讨论。		
		HandlerExecutionChain handler = hm.getHandler(request);
		if (handler != null) {
			return handler;
		}
	}
	return null;
}
2.3 getHandlerAdapter方法

在获取到HandlerExecutionChain类实例之后,SpringMVC并没有直接对找到的handler进行处理;而是再次引入一个中间层——将对当前Object类型的Handler进行适配, 适配为对应的HandlerAdapter中间层作为软件开发中的银弹,再一次在这里得以实证。

// DispatcherServlet类定义的getHandlerAdapter方法
protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
	// 关于HandlerAdapter接口,可以参见下面的专门讲解
	for (HandlerAdapter ha : this.handlerAdapters) {
		// 将权限下方给每个HandlerAdapter, 由HandlerAdapter自主决定是否适配这个Handler(注意这个方法参数handler是Object类型)
		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");
}

3. HandlerMapping接口

public interface HandlerMapping {
	// 省略了其他常量和注释

	// 声明的唯一方法`getHandler`
	HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception;
}

该方法的参数为request, 而返回值则是HandlerExecutionChain类型。
1. 返回值HandlerExecutionChain本身就是一个扩展性非常强的类。其内部的Object类型的handler以及HandlerInterceptor类型的interceptor集合至少能吞掉90%的自定义需求。(注意此类出现于2003年,至今没有出现子类)。
2. 而方法参数request也符合《Clean Code》里Bob大叔对函数的建议——参数要尽可能少;再加上Servlet规范的精妙设计,所以这个HandlerMapping接口的设计堪称完美

4. HandlerAdapter接口

public interface HandlerAdapter {
	// 为节省篇幅, 我把注释删除掉了

	boolean supports(Object handler);

	ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception;

	long getLastModified(HttpServletRequest request, Object handler);
}

这个接口的设计也是相当精妙。虽然在Spring的源码里第一次体会到主从关系颠倒是在SmartApplicationListener接口声明中,但这里的再次出现依然让我惊叹这种思路的精妙——由子元素自己决定是否支持适配这个Object类型的handler, 如果你支持,那么调度者才去调用你实现的handle方法。

5. 实例详解

这里以以下的代码为示例,来讲解下SpringMVC的处理流程,顺带给各位看官演示下阅读源码的一种方式。至于为什么是下面这段代码——因为最近在给公司研发部门制定一整套完整的代码规范。而以下Controller层的代码规范参考了《华为简约代码规范》。

// ----------- Controller层
//@RequestMapping(value = "/standardmethod2", method = { RequestMethod.POST,RequestMethod.GET })
// GetMapping("/standardmethod2")  // 同时注解GetMapping,PostMapping只会生效一个 
@PostMapping("/standardmethod2")
@ResponseBody // 必须要有; `RequestResponseBodyMethodProcessor`类的supportsReturnType方法使用到了
public ResponseBean<Map<String, String>> standardmethod2(long id) {
	return ResponseBean.of(Collections.singletonMap("YWID", "123"));		
}

// ----------- spring-mvc.xml中 ;更多详情看下面给出的链接
<mvc:annotation-driven>
	<mvc:message-converters register-defaults="true">
		<!-- 配置Fastjson支持 -->
		<bean class="com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter">
			<property name="supportedMediaTypes">
				<list>
					<value>text/html;charset=UTF-8</value>
					<value>application/json</value>
				</list>
			</property>
			<property name="features">
				<list>
					<value>WriteMapNullValue</value>
					<value>QuoteFieldNames</value>
				</list>
			</property>
		</bean>
	</mvc:message-converters>
</mvc:annotation-driven>

现在我想知道SpringMVC是如何调用这个方法的?那好,我在这个方法体里打个断点。于是我们得到了下面这幅堆栈图。 笔者的笔记本屏幕大小有限,只能截取这么多了。

ansible 字符串匹配 ansible实现截取字符串_源码_02

5.1 RequestMappingHandlerAdapter

  1. 全称为org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter
  2. 对于我们使用@RequestMapping注解的方法,DispatcherServlet.doDispatch中的
    HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler()); 返回值ha就是RequestMappingHandlerAdapter类型。
  3. 看以上的堆栈图就可以发现,最终主流程会回调本类中声明的invokeHandlerMethod方法来调用用户自定义的方法(standardmethod2(long id))。
  4. 其实invokeHandlerMethod方法内部实现细节表明:调用自定义方法来获取返回值的操作最终是被委托给了ServletInvocableHandlerMethod类来实现了

5.2 ServletInvocableHandlerMethod

全称是org.springframework.web.method.support.InvocableHandlerMethod

// ---------- ServletInvocableHandlerMethod.invokeAndHandle
public void invokeAndHandle(ServletWebRequest webRequest, ModelAndViewContainer mavContainer,
		Object... providedArgs) throws Exception {

	// 这里就是真正调用自定义方法, 获取用户方法的返回值。
	Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs);
	setResponseStatus(webRequest);

	// 如果我们在自定义的方法里返回null的话, 就会进入这条分支了
	if (returnValue == null) {
		if (isRequestNotModified(webRequest) || getResponseStatus() != null || mavContainer.isRequestHandled()) {
			mavContainer.setRequestHandled(true);
			return;
		}
	}
	else if (StringUtils.hasText(getResponseStatusReason())) {
		mavContainer.setRequestHandled(true);
		return;
	}

	mavContainer.setRequestHandled(false);
	try {
		// 使用注册的returnValueHandler集合处理返回值
		// 这里的returnValueHandlers是HandlerMethodReturnValueHandlerComposite类型。(见下方的详解)
		// 我们在示例中会在spring-mvc.xml中注册的FastJsonHttpMessageConverter就是在这个方法里被调用的。
		this.returnValueHandlers.handleReturnValue(
				returnValue, getReturnValueType(returnValue), mavContainer, webRequest);
	}
	catch (Exception ex) {
		throw ex;
	}
}

// ---------- ServletInvocableHandlerMethod.invokeForRequest(其实是基类中定义的)
public Object invokeForRequest(NativeWebRequest request, ModelAndViewContainer mavContainer,
		Object... providedArgs) throws Exception {
	// 获取 将要传递给我们自定义方法 的参数
	Object[] args = getMethodArgumentValues(request, mavContainer, providedArgs);
	if (logger.isTraceEnabled()) {
		logger.trace("Invoking '" + ClassUtils.getQualifiedMethodName(getMethod(), getBeanType()) +
				"' with arguments " + Arrays.toString(args));
	}
	Object returnValue = doInvoke(args);
	if (logger.isTraceEnabled()) {
		logger.trace("Method [" + ClassUtils.getQualifiedMethodName(getMethod(), getBeanType()) +
				"] returned [" + returnValue + "]");
	}
	return returnValue;
}

5.3 HandlerMethodReturnValueHandlerComposite

直接上方法实现

// HandlerMethodReturnValueHandlerComposite重载的handleReturnValue方法
@Override
public void handleReturnValue(Object returnValue, MethodParameter returnType,
		ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception {
	// 挑选出合适的HandlerMethodReturnValueHandler
	// 这里的技巧依然是权限下放, 由各个HandlerMethodReturnValueHandler自己决定是否处理该类型和值
	HandlerMethodReturnValueHandler handler = selectHandler(returnValue, returnType);
	if (handler == null) {
		throw new IllegalArgumentException("Unknown return value type: " + returnType.getParameterType().getName());
	}

	// 在本次示例中, 这个hanlder为RequestResponseBodyMethodProcessor类型(见下方的详解)
	handler.handleReturnValue(returnValue, returnType, mavContainer, webRequest);
}

这里我们列出HandlerMethodReturnValueHandlerComposite类中的returnValueHandlers字段里的Item:

1. org.springframework.web.servlet.mvc.method.annotation.ModelAndViewMethodReturnValueHandler
2. org.springframework.web.method.annotation.ModelMethodProcessor
3. org.springframework.web.servlet.mvc.method.annotation.ViewMethodReturnValueHandler
4. org.springframework.web.servlet.mvc.method.annotation.ResponseBodyEmitterReturnValueHandler
5. org.springframework.web.servlet.mvc.method.annotation.StreamingResponseBodyReturnValueHandler
6. org.springframework.web.servlet.mvc.method.annotation.HttpEntityMethodProcessor
7. org.springframework.web.servlet.mvc.method.annotation.HttpHeadersReturnValueHandler
8. org.springframework.web.servlet.mvc.method.annotation.CallableMethodReturnValueHandler
9. org.springframework.web.servlet.mvc.method.annotation.DeferredResultMethodReturnValueHandler
10. org.springframework.web.servlet.mvc.method.annotation.AsyncTaskMethodReturnValueHandler
11. org.springframework.web.method.annotation.ModelAttributeMethodProcessor
12. 
org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor
13. org.springframework.web.servlet.mvc.method.annotation.ViewNameMethodReturnValueHandler
14. org.springframework.web.method.annotation.MapMethodProcessor
15. org.springframework.web.method.annotation.ModelAttributeMethodProcessor

5.4 RequestResponseBodyMethodProcessor

该类实现的supportsReturnType方法说明了我们在自定义方法上标注@ResponseBody的作用

// RequestResponseBodyMethodProcessor覆写的handleReturnValue方法
@Override
public void handleReturnValue(Object returnValue, MethodParameter returnType,
		ModelAndViewContainer mavContainer, NativeWebRequest webRequest)
		throws IOException, HttpMediaTypeNotAcceptableException, HttpMessageNotWritableException {

	mavContainer.setRequestHandled(true);
	ServletServerHttpRequest inputMessage = createInputMessage(webRequest);
	ServletServerHttpResponse outputMessage = createOutputMessage(webRequest);

	// Try even with null return value. ResponseBodyAdvice could get involved.
	// 示例中在spring-mvc.xml中注册的FastJsonHttpMessageConverter将在这个方法里将返回的ResponseBean示例转换为JSON字符串
	writeWithMessageConverters(returnValue, returnType, inputMessage, outputMessage);
}

依然是列举下RequestResponseBodyMethodProcessor类中的 messageConverters 集合字段中存储的Item

1. 
com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter
2. org.springframework.http.converter.ByteArrayHttpMessageConverter
3. org.springframework.http.converter.StringHttpMessageConverter
4. org.springframework.http.converter.ResourceHttpMessageConverter
5. org.springframework.http.converter.xml.SourceHttpMessageConverter
6. org.springframework.http.converter.support.AllEncompassingFormHttpMessageConverter
7. org.springframework.http.converter.xml.Jaxb2RootElementHttpMessageConverter

5.5 补充

  1. 注意在本示例中,最终mv = ha.handle(processedRequest, response, mappedHandler.getHandler());返回的mv为null。

Links

  1. 《Spring源码深度解析》 – P320
  2. http://jinnianshilongnian.iteye.com/blog/1602617