前言
DispatcherServlet继承httpServlet,所以实质上DispatcherServlet也是一个Servlet,这一点在DispatcherServlet初始化时就证明了。在tomcat执行某个servlet的时候,首先会调用service方法,然后在service方法中判断是哪一种请求方法,在分配到对应的请求方法处理函数去处理请求。在探究DispatcherServlet处理请求的过程,也会从service方法开始。
DispatcherServlet请求处理过程
service(HttpServletRequest request, HttpServletResponse response)方法
protected void service(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
HttpMethod httpMethod = HttpMethod.resolve(request.getMethod());
if (httpMethod == HttpMethod.PATCH || httpMethod == null) {
processRequest(request, response);
}
else {
super.service(request, response);
}
}
HttpMethod是一个枚举类,主要设置了请求的多种方式(post,get,head,put,patch等等),HttpMethod.resolve方法主要检查request的请求方法是其中的哪一种,如果都不是则返回null。这里我们一般是get,post,put,delete方法用的较多,所以执行else语句的时候较多。
super.service(HttpServletRequest req, HttpServletResponse resp)方法
protected void service(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException
{
String method = req.getMethod();
if (method.equals(METHOD_GET)) {
long lastModified = getLastModified(req);
if (lastModified == -1) {
doGet(req, resp);
} else {
long ifModifiedSince = req.getDateHeader(HEADER_IFMODSINCE);
if (ifModifiedSince < lastModified) {
maybeSetLastModified(resp, lastModified);
doGet(req, resp);
} else {
resp.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
}
}
} else if (method.equals(METHOD_HEAD)) {
long lastModified = getLastModified(req);
maybeSetLastModified(resp, lastModified);
doHead(req, resp);
} else if (method.equals(METHOD_POST)) {
doPost(req, resp);
} else if (method.equals(METHOD_PUT)) {
doPut(req, resp);
} else if (method.equals(METHOD_DELETE)) {
doDelete(req, resp);
}
.....
}
可以看到super.service方法就是前言中所说的那样,根据请求方式的不同选择相对应的方法来处理。
可以看到FrameworkServlet类中重写了Httpservlet中的各种处理对应请求方式的处理函数
protected final void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
processRequest(request, response);
}
@Override
protected final void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
processRequest(request, response);
}
@Override
protected final void doPut(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
processRequest(request, response);
}
@Override
protected final void doDelete(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
processRequest(request, response);
}
他们都调用统一个方法来处理
processRequest(request, response)方法
protected final void processRequest(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
.....
doService(request, response);
....
}
processRequest方法中比较重要的就是doService方法
doService(HttpServletRequest request, HttpServletResponse response)方法
protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {
// 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<>();
Enumeration<?> attrNames = request.getAttributeNames();
while (attrNames.hasMoreElements()) {
String attrName = (String) attrNames.nextElement();
if (this.cleanupAfterInclude || attrName.startsWith(DEFAULT_STRATEGIES_PREFIX)) {
attributesSnapshot.put(attrName, request.getAttribute(attrName));
}
}
}
// Make framework objects available to handlers and view objects.
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());
if (this.flashMapManager != null) {
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(request, response);
}
finally {
if (!WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) {
// Restore the original attribute snapshot, in case of an include.
if (attributesSnapshot != null) {
restoreAttributesAfterInclude(request, attributesSnapshot);
}
}
}
}
在doservice方法中也只是做了一些前期的准备工作,保存一些属性,在request中设置处理请求的工具(localeResolver,themeResolver),还有IOC容器。
接着调用了doDispatch(request, response)方法。
doDispatch(request, response)(重点)
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.查看是否是 form表单上传参数 如果是将request包装成
processedRequest = checkMultipart(request);
multipartRequestParsed = (processedRequest != request);
// 2.获得handler----(这里的handler是指RequestMappingHandlerMapping,BeanNameUrlHandlerMapping等等)
mappedHandler = getHandler(processedRequest);
if (mappedHandler == null) {
//如果没有找到对应的handler,则通过response.sendError(404);
noHandlerFound(processedRequest, response);
return;
}
//3.获得handlerAdapter
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
//4.如果请求方法是 get/head 则查看处理请求的类或者方法是否发生改变
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;
}
}
// 5.执行拦截器的preHandler方法
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}
//6.执行处理请求的方法并得到ModeAndView
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
if (asyncManager.isConcurrentHandlingStarted()) {
return;
}
//7.在ModelAndView 不为空但是view = null 的时候 使用RequestToViewNameTranslator获得默认的view
applyDefaultViewName(processedRequest, mv);
//8.执行拦截器的postHandler方法
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);
}
//9.处理异常,解析View并执行view.render方法跳转页面
processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
}
catch (Exception ex) {
triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
}
catch (Throwable err) {
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);
}
}
}
}
总结
第一步:checkMultipart(request); 查看是否配置了MulqtipartResolver(MulqtipartResolver 组件在处理一个请求的时候不是必须的,所以在dispatcherServlet 初始化时并没有设置一个默认的MultipartResolver组件),如果配置了,则检测这个请求中是否上传了文件,如果是,则使用配置的MultipartResolver.resolveMultipart方法将request包装成一个MultipartHttpServletRequest,从这个对象中可以获得一个MultipartFile对象,然后获得文件的相关信息。
第二步:获得一个HandlerMapping,用于找到请求url对应的处理类或者方法。如果没有找到对应的handlermapping,则返回404.
第三步:获得一个HandlerAdapter,用于在执行处理方法前的一些预处理和执行处理方法。
第四步:查看请求url对应的处理类或者方法是否发生过改变(通过last-modified),如果没有,则不需要处理该请求。如果发生了改变,则处理请求。
第五步:执行interceptor的preHandle方法。
第六步:通过handlerAdapter执行处理请求的方法并返回ModelAndView对象
第七步:当返回的ModelAndView对象不为空但是没有view的时候,就获得defaultViewName。通过RequestToViewNameTranslator来解析request对象来获得。
第八步:执行interceptor的postHandler方法
第九步:处理方法执行后的结果。则其中包括这样几个步骤:
- 处理抛出的异常
当抛出的异常是一个ModelAndViewDefiningException,直接调用其getModelAndView方法获得一个ModelAndView就行了。不是ModelAndViewDefiningException异常时,使用HandlerExceptionResolver来处理异常 - 处理View
首先使用LocaleResolver来处理视图语言。
然后使用ViewResolver来处理viewName,找到对应的View对象。
执行View.render方法 - 执行interceptor的triggerAfterCompletion方法