上一篇文章我们已经讨论过了
DispatcherServlet
类的初始化问题,本篇博客则就SpringMVC处理一次完整的请求进行讨论。
由继承图来看: Servlet
, ServletConfig
功能被合并在一个类中。但又通过不同的接口进行功能分离。
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);
}
}
}
}
先分析下这两行代码
HandlerExecutionChain mappedHandler = getHandler(processedRequest);
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
HandlerExecutionChain
类就是围绕该Object类型的handler进行封装的一个Chain。HandlerAdapter
接口也是针对该Object类型的handler进行的适配 。然后我们来具体分析 getHandler
和 getHandlerAdapter
方法
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;
}
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");
}
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
接口的设计堪称完美。
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
方法。
这里以以下的代码为示例,来讲解下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">
<bean class="com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter">
<property name="supportedMediaTypes">
<list>
<value>text/html;charset=UTF-8value>
<value>application/jsonvalue>
list>
property>
<property name="features">
<list>
<value>WriteMapNullValuevalue>
<value>QuoteFieldNamesvalue>
list>
property>
bean>
mvc:message-converters>
mvc:annotation-driven>
现在我想知道SpringMVC是如何调用这个方法的?那好,我在这个方法体里打个断点。于是我们得到了下面这幅堆栈图。 笔者的笔记本屏幕大小有限,只能截取这么多了。
RequestMappingHandlerAdapter
类org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter
。@RequestMapping
注解的方法,DispatcherServlet.doDispatch
中的 HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
RequestMappingHandlerAdapter
类型。invokeHandlerMethod
方法来调用用户自定义的方法(standardmethod2(long id)
)。invokeHandlerMethod
方法内部实现细节表明:调用自定义方法来获取返回值的操作最终是被委托给了ServletInvocableHandlerMethod
类来实现了。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;
}
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:
org.springframework.web.servlet.mvc.method.annotation.ModelAndViewMethodReturnValueHandler
org.springframework.web.method.annotation.ModelMethodProcessor
org.springframework.web.servlet.mvc.method.annotation.ViewMethodReturnValueHandler
org.springframework.web.servlet.mvc.method.annotation.ResponseBodyEmitterReturnValueHandler
org.springframework.web.servlet.mvc.method.annotation.StreamingResponseBodyReturnValueHandler
org.springframework.web.servlet.mvc.method.annotation.HttpEntityMethodProcessor
org.springframework.web.servlet.mvc.method.annotation.HttpHeadersReturnValueHandler
org.springframework.web.servlet.mvc.method.annotation.CallableMethodReturnValueHandler
org.springframework.web.servlet.mvc.method.annotation.DeferredResultMethodReturnValueHandler
org.springframework.web.servlet.mvc.method.annotation.AsyncTaskMethodReturnValueHandler
org.springframework.web.method.annotation.ModelAttributeMethodProcessor
org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor
// 本次的主角org.springframework.web.servlet.mvc.method.annotation.ViewNameMethodReturnValueHandler
org.springframework.web.method.annotation.MapMethodProcessor
org.springframework.web.method.annotation.ModelAttributeMethodProcessor
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
// 本次主角,也就是我们在spring-mvc.xml中注册的。
1. org.springframework.http.converter.ByteArrayHttpMessageConverter
1. org.springframework.http.converter.StringHttpMessageConverter
1. org.springframework.http.converter.ResourceHttpMessageConverter
1. org.springframework.http.converter.xml.SourceHttpMessageConverter
1. org.springframework.http.converter.support.AllEncompassingFormHttpMessageConverter
1. org.springframework.http.converter.xml.Jaxb2RootElementHttpMessageConverter
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
返回的mv为null。