1、前面我们花了两篇文章把SpringMVC的初始化流程讲了一遍,今天我们正式进入到SpringMVC的各大组件剖析,我们第一剖析的就是这个SpringMVC的前端控制器DispatcherServlet。
2、DispatcherServlet工作流程解析
2.1、DispatcherServlet是一个标准的Servlet, 那么它肯定实现的Servlet的标准方法:
void service(ServletRequest var1, ServletResponse var2)
我们了解其实现的整个流程得出,我们所有的请求都会在DispatcherServlet的doService方法中处理
doService(HttpServletRequest request, HttpServletResponse response)
DispatcherServlet的doService方法源码:
protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {
if (this.logger.isDebugEnabled()) {
String resumed = WebAsyncUtils.getAsyncManager(request).hasConcurrentResult() ? " resumed" : "";
this.logger.debug("DispatcherServlet with name '" + this.getServletName() + "'" + resumed + " processing " + request.getMethod() + " request for [" + getRequestUri(request) + "]");
}
Map<String, Object> attributesSnapshot = null;
if (WebUtils.isIncludeRequest(request)) {
attributesSnapshot = new HashMap();
Enumeration attrNames = request.getAttributeNames();
label108:
while(true) {
String attrName;
do {
if (!attrNames.hasMoreElements()) {
break label108;
}
attrName = (String)attrNames.nextElement();
} while(!this.cleanupAfterInclude && !attrName.startsWith("org.springframework.web.servlet"));
attributesSnapshot.put(attrName, request.getAttribute(attrName));
}
}
向请求中添加当前的SpringMVC应用上下文,这样我们在Controller中可以中获取如下方式:
/*
WebApplicationContext attribute =
(WebApplicationContext) request.getAttribute(DispatcherServlet.WEB_APPLICATION_CONTEXT_ATTRIBUTE);
*/
request.setAttribute(WEB_APPLICATION_CONTEXT_ATTRIBUTE, this.getWebApplicationContext());
同样的方式把DispatcherServlet的本地信息解析器localeResolver也设置到请求中
request.setAttribute(LOCALE_RESOLVER_ATTRIBUTE, this.localeResolver);
把DispatcherServlet的主题解析器也添加到请求中
request.setAttribute(THEME_RESOLVER_ATTRIBUTE, this.themeResolver);
把DispatcherServlet的主题源设置到请求中。
request.setAttribute(THEME_SOURCE_ATTRIBUTE, this.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方法去处理请求,此处很重要!!!!
this.doDispatch(request, response);
} finally {
if (!WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted() && attributesSnapshot != null) {
this.restoreAttributesAfterInclude(request, attributesSnapshot);
}
}
}
在doService方法中调用了doDispatch方法来进行请求的处理,doDispatch方法源码如下:
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
HttpServletRequest processedRequest = request;
HandlerExecutionChain mappedHandler = null;
boolean multipartRequestParsed = false;
WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
try {
ModelAndView mv = null;
Exception dispatchException = null;
try {
1、解析是否有文件上传,检查的方式就是使用multipartResolver文件上传解析器根据请求去解析,具体怎么解析后面详细说multipartResolver组件的时候会分析。
processedRequest = checkMultipart(request);
multipartRequestParsed = (processedRequest != request);
// Determine handler for the current request.
2、获取一个包装过的处理器,获取的方式是使用DispatcherServlet以及初始化好的HandlerMapping处理器映射器列表去获取,
有多个HandlerMapping的话,循环调用,一旦获取到处理器直接返回且结束循环。具体怎么获取在讲解HandlerMapping组件的时候会详细剖析。
!!!重点强调一下,什么是包装过的处理器,其实就是HandlerExecutionChain 这个类中有SpringMVC的拦截器列表,
还有一个很重要的成员属性private final Object handler; 这个就是真正意义上的处理器,类型是一个Object,因为在不同处理器映射器中,
对处理器的定义是不一样的,比如RequestMappingHandlerMapping中此类型就是HandlerMethod也就是Controller中的每一个方法描述。
mappedHandler = getHandler(processedRequest);
if (mappedHandler == null || mappedHandler.getHandler() == null) {
如果使用HandlerMappings处理器映射器列表都没找到处理器,就调用noHandlerFound方法,这个方法会将response.sendError(404); 哈哈 头疼的404原来是在这里设置的啊
noHandlerFound(processedRequest, response);
return;
}
// Determine handler adapter for the current request.
3、如果使用处理器映射器找到了包装过的处理器,那就使用真正的处理器(也就是被包装的处理器)去寻找一个处理器适配器,
寻找的方式就是循环的看看DispatcherServlet的handlerAdapters列表有没有支持当前处理器的,一旦有支持的就直接返回处理器适配器且结束循环。如果没有那就直接抛出异常ServletException。
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;
}
}
使用包装过的处理器去执行SpringMVC的拦截器的前置方法,如果有其中一个拦截器返回的false就直接结束请求。
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}
// Actually invoke the handler.
4、使用获取到的处理器适配器HnadlerAdapter去执行真正的处理器,返回一个ModelAndView实例。
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
if (asyncManager.isConcurrentHandlingStarted()) {
return;
}
5、如果返回的ModelAndView中没有view,那就设置ModelAndView实例的view=默认的viewName
applyDefaultViewName(processedRequest, mv);
6、使用包装过多处理器去执行SpringMVC的拦截器的后置方法,后置方法执行所有的拦截器的后置方法。
mappedHandler.applyPostHandle(processedRequest, response, mv);
}
catch (Exception ex) {
dispatchException = ex;
}
catch (Throwable err) {
// As of 4.3, we're processing Errors thrown from handler methods as well,
// making them available for @ExceptionHandler methods and other scenarios.
dispatchException = new NestedServletException("Handler dispatch failed", err);
}
7、处理处理器执行结果,如果处理器执行抛出异常,也是在此处处理。并且也会在此步骤去执行包装过的处理器中的所有拦截器的afterCompletion方法,执行方式for循环调用全部。
processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
}
catch (Exception ex) {
如果包装过的整个处理链路任何一个环节出现异常,都会执行包装过的处理器里的SpringMVC拦截器的afterCompletion方法,执行方式for循环调用全部。
triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
}
catch (Throwable err) {
如果包装过的整个处理链路任何一个环节出现系统级别的错误,都会执行包装过的处理器里的SpringMVC拦截器的afterCompletion方法,执行方式for循环调用全部。
triggerAfterCompletion(processedRequest, response, mappedHandler,
new NestedServletException("Handler processing failed", 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);
}
}
}
}
以上就是SpringMVC的前端控制DispatcherServlet的整体工作原理,这个与我们之前描述SpringMVC的整体工作流程的图片是对应的,如下:
在下一篇文章中,我们将会分析文件上传解析器。