所有的http请求都会交给DispatcherServlet类的doDispatch方法进行处理,将DispatcherServlet.doDispatch函数的javadoc复制到下面:

/*
* Process the actual dispatching to the handler.
*
* The handler will be obtained by applying the servlet's HandlerMappings in
* order.The HandlerAdapter will be obtained by querying the servlet's
* installed HandlerAdapters to find the first that supports the handler
* class.
*
* All HTTP methods are handled by this method. It's up to HandlerAdapters
* or handlers themselves to decide which methods are acceptable.
*/
void org.springframework.web.servlet.DispatcherServlet.doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception;

下面分析doDispatch方法的流程,采用注释源码的方式:

 protected void doDispatch(HttpServletRequest request,
HttpServletResponse response) throws Exception { // processedRequest是经过checkMultipart方法处理过的request请求
HttpServletRequest processedRequest = request;
/**
* Handler execution chain, consisting of handler object and any handler
* interceptors. Returned by HandlerMapping's HandlerMapping.getHandler
* method. 看看HandlerExecutionChain类的属性就很清楚了:
*
public class HandlerExecutionChain { private final Object handler; //这个就是和该请求对应的handler处理方法 //里面记录了所有的(any handler interceptors)和该请求相关的拦截器
private HandlerInterceptor[] interceptors; private List<HandlerInterceptor> interceptorList; private int interceptorIndex = -1; //...
}
*
*/
HandlerExecutionChain mappedHandler = null;
boolean multipartRequestParsed = false; WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request); try {
ModelAndView mv = null;
Exception dispatchException = null; try {
processedRequest = checkMultipart(request);
multipartRequestParsed = (processedRequest != request); // Determine handler for the current request.Return a handler
// and any interceptors for this request.
/*
* 得到的mappedHandler包含一个请求的handler处理方法以及与该请求相关的所有拦截器
*
* DispatcherServlet.getHandler方法会在底层调用HandlerMapping.getHandler方法
* ,这个方法中会遍 历DispatcherServlet中的private List<HandlerMapping>
* handlerMappings链表,找到能够处理当前 request请求的第一个HandlerMapping实例并返回:
*
protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
for (HandlerMapping hm : this.handlerMappings) {
HandlerExecutionChain handler = hm.getHandler(request);
if (handler != null) {
return handler;
}
}
return null;
}
*
*/
mappedHandler = getHandler(processedRequest);
// 如果没有找到和该请求相对应的mappedHandler,那么就会直接返回,并应答noHandlerFound异常
if (mappedHandler == null || mappedHandler.getHandler() == null) {
noHandlerFound(processedRequest, response);
return;
} // Determine handler adapter for the current request.
/*
* HandlerAdapter: 它是一个接口public interface HandlerAdapter
* 看看源码上的说明:The DispatcherServlet accesses all installed
* handlers through this interface, meaning that it does not
* contain code specific to any handler type.
*
* 从后面的源码看出,在使用@RequestMapping注解标注handler方法的时候,获取到的是HandlerAdapter的
* RequestMappingHandlerAdapter实现类的一个对象。
*
* 可以看看DispatcherServlet.getHandlerAdapter方法的定义,这个对理解上回很有帮助,我们会发现
* ,getHandlerAdapter 方法和上面提到的getHandler方法一样都是寻找第一个可用的作为返回结果:
*
*
protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
//this.handlerAdapters的定义是 private List<HandlerAdapter> handlerAdapters
for (HandlerAdapter ha : this.handlerAdapters) {
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");
}
*
*/
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;
}
} // Apply preHandle methods of registered interceptors.
/*
* 会调用所有注册拦截器的preHandle方法,如果preHandle方法的返回结果为true,则会继续执行下面的程序,
* 否则会直接返回。
*
* 分析一下HandlerExecutionChain.applyPreHandle方法的源码 :
boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception {
//从上面的HandlerExecutionChain定义处可以看见有个interceptors,还有一个interceptorList。不知道有什么区别??!
HandlerInterceptor[] interceptors = getInterceptors();
//如果已经注册有拦截器,则遍历拦截器
if (!ObjectUtils.isEmpty(interceptors)) {
for (int i = 0; i < interceptors.length; i++) {
HandlerInterceptor interceptor = interceptors[i];
//如果注册拦截器的preHandle方法返回一个false,则该applyPreHandle方法就会返回false,从而在doDispatcher中的代码就不会往下执行了
if (!interceptor.preHandle(request, response, this.handler)) { //这个方法要注意,它会调用所有已经成功执行的拦截器的afterCompletion方法,而且是反序调用的过程,可以分析triggerAfterCompletion
//的源代码,主要是利用interceptorIndex反减的方式实现的。下面是源码的英文注释:
//Trigger afterCompletion callbacks on the mapped HandlerInterceptors.
//Will just invoke afterCompletion for all interceptors whose preHandle invocation
//has successfully completed and returned true.
triggerAfterCompletion(request, response, null);
return false;
}
//没成功执行一个拦截器的preHandle方法,其interceptorIndex就会增加1;原始值为-1。
this.interceptorIndex = i;
}
}
return true;
}
*
*
* 顺带看看triggerAfterCompletion的源代码,很容易理解为什么拦截器的afterCompletion方法是反序执行的:
* void triggerAfterCompletion(HttpServletRequest request, HttpServletResponse response, Exception ex)
throws Exception { HandlerInterceptor[] interceptors = getInterceptors();
if (!ObjectUtils.isEmpty(interceptors)) {
for (int i = this.interceptorIndex; i >= 0; i--) {
HandlerInterceptor interceptor = interceptors[i];
try {
interceptor.afterCompletion(request, response, this.handler, ex);
}
catch (Throwable ex2) {
logger.error("HandlerInterceptor.afterCompletion threw exception", ex2);
}
}
}
}
*
*
*/
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
} // Actually invoke the handler.
/*
* 在这个函数里面会真正的执行request请求相对于的handler方法,可以想象:在真正调用方法之前还会有很多的
* 先前处理。在这里仅仅是分析出大概的代码执行流程,其细节的部分在后面的单独模块源码分析的时候做详细的讲解。
* 上面讲解到HandlerAdapter是一个接口:public interface HandlerAdapter,那么必然会有很多
* 中实现类,在采用注解@RequstMapping的方式标注handler的情况下,ha.handle方法会在底层调用具体的
* HandlerAdapter类实现方法RequestMappingHandlerAdapter.handleInternal
*
* 分析一下RequestMappingHandlerAdapter.handleInternal的源代码:
protected ModelAndView handleInternal(HttpServletRequest request,
HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
//好像是看control的类定义处是否使用了@SessionAttributes注解,checkAndPrepare方法有什么作用???
if (getSessionAttributesHandler(handlerMethod).hasSessionAttributes()) {
// Always prevent caching in case of session attribute management.
checkAndPrepare(request, response, this.cacheSecondsForSessionAttributeHandlers, true);
}
else {
// Uses configured default cacheSeconds setting.
checkAndPrepare(request, response, true);
} // Execute invokeHandlerMethod in synchronized block if required.
// 这里是个值得注意的地方,synchronizeOnSession的值默认为false,如果通过某个方法使得其为true,那么request对应的handler
// 将会被放在同步快中进行处理。在什么时机下,使用什么方法才能将其设置为true呢???
if (this.synchronizeOnSession) {
HttpSession session = request.getSession(false);
if (session != null) {
Object mutex = WebUtils.getSessionMutex(session);
// 将handler放在同步块中处理
synchronized (mutex) {
return invokeHandleMethod(request, response, handlerMethod);
}
}
}
//在invokeHandleMethod中会①将所有标注有@ModelAttrib的方法都执行一遍,②调用invokeAndHandle(webRequest, mavContainer)
//方法,在这里面调用handler方法,③最后调用getModelAndView(mavContainer, modelFactory, webRequest)方法的到ModelAndView。
//invokeHandleMethod这个方法还有很多东西要分析,留在后面。
//从上面的③我们可以看出,无论handler采用哪种模型化处理方式,最后都是将结果转化为ModelAndView
return invokeHandleMethod(request, response, handlerMethod);
}
*/
mv = ha.handle(processedRequest, response,
mappedHandler.getHandler()); if (asyncManager.isConcurrentHandlingStarted()) {
return;
} applyDefaultViewName(request, mv);
/*
* 调用request相关的拦截器的postHandle方法,注意,这个也是反序调用的。看看源代码:
*
void applyPostHandle(HttpServletRequest request, HttpServletResponse response, ModelAndView mv) throws Exception {
HandlerInterceptor[] interceptors = getInterceptors();
if (!ObjectUtils.isEmpty(interceptors)) {
//注意,这里也是反序执行,而且是所有成功执行了的postHandle拦截器
for (int i = interceptors.length - 1; i >= 0; i--) {
HandlerInterceptor interceptor = interceptors[i];
//这里传入的参数中有mv,也就是说,我们是有办法在拦截器的postHandle方法中修改已经返回的mv
interceptor.postHandle(request, response, this.handler, 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
if (mappedHandler != null) {
mappedHandler.applyAfterConcurrentHandlingStarted(
processedRequest, response);
}
} else {
// Clean up any resources used by a multipart request.
if (multipartRequestParsed) {
cleanupMultipart(processedRequest);
}
}
}
}

看完源代码就可以总结出doDispath方法中处理http请求的流程了:

6、SpringMVC源码分析(1):分析DispatcherServlet.doDispatch方法,了解总体流程的更多相关文章

  1. SpringMVC源码情操陶冶-DispatcherServlet

    本文对springmvc核心类DispatcherServlet作下简单的向导,方便博主与读者查阅 DispatcherServlet-继承关系 分析DispatcherServlet的继承关系以及主 ...

  2. SpringMVC源码情操陶冶-DispatcherServlet简析(二)

    承接前文SpringMVC源码情操陶冶-DispatcherServlet类简析(一),主要讲述初始化的操作,本文将简单介绍springmvc如何处理请求 DispatcherServlet#doDi ...

  3. springMVC源码分析--DispatcherServlet请求获取及处理

    在之前的博客springMVC源码分析--容器初始化(二)DispatcherServlet中我们介绍过DispatcherServlet,是在容器初始化过程中出现的,我们之前也说过Dispatche ...

  4. SpringMVC源码分析--容器初始化(五)DispatcherServlet

    上一篇博客SpringMVC源码分析--容器初始化(四)FrameworkServlet我们已经了解到了SpringMVC容器的初始化,SpringMVC对容器初始化后会进行一系列的其他属性的初始化操 ...

  5. springMVC源码分析--容器初始化(二)DispatcherServlet

    在上一篇博客springMVC源码分析--容器初始化(一)中我们介绍了spring web初始化IOC容器的过程,springMVC作为spring项目中的子项目,其可以和spring web容器很好 ...

  6. SpringMVC源码分析(3)DispatcherServlet的请求处理流程

    <springmvc源码分析(2)dispatcherservlet的初始化>初始化DispatcherServlet的多个组件. 本文继续分析DispatcherServlet解析请求的 ...

  7. SpringMVC源码分析系列

    说到java的mvc框架,struts2和springmvc想必大家都知道,struts2的设计基本上完全脱离了Servlet容器,而springmvc是依托着Servlet容器元素来设计的,同时sp ...

  8. springMVC源码分析之拦截器

    一个东西用久了,自然就会从仅使用的层面上升到探究其原理的层面,在javaweb中springmvc更是如此,越是优秀的框架,其底层实现代码更是复杂,而在我看来,一个优秀程序猿就相当于一名武林高手,不断 ...

  9. 8、SpringMVC源码分析(3):分析ModelAndView的形成过程

    首先,我们还是从DispatcherServlet.doDispatch(HttpServletRequest request, HttpServletResponse response) throw ...

  10. 7、SpringMVC源码分析(2):分析HandlerAdapter.handle方法,了解handler方法的调用细节以及@ModelAttribute注解

    从上一篇 SpringMVC源码分析(1) 中我们了解到在DispatcherServlet.doDispatch方法中会通过 mv = ha.handle(processedRequest, res ...

随机推荐

  1. 前端内容安全策略(csp)

    什么是CSP CSP全称Content Security Policy ,可以直接翻译为内容安全策略,说白了,就是为了页面内容安全而制定的一系列防护策略. 通过CSP所约束的的规责指定可信的内容来源( ...

  2. 剑指offer-青蛙变态跳台阶-全概率公式

  3. Vault 0.10包含了web ui

    Vault 是一个很不错的访问控制,secret api key 管理工具 新的0.10 有好多新的功能的添加,最棒的是有一个web ui 了 包含的新特性如下: K/V Secrets Engine ...

  4. FastAdmin composer json 版本说明

    来源于 FastAdmin 执行 composer update 后将 ThinkPHP 升级到了 V5.1. FastAdmin  是基于 ThinkPHP 5.0.x 开发的,而 ThinkPHP ...

  5. java 方向术语

    缩写 英文 中文意思 POJO Plain Ordinary Java Object 简单的Java对象 slf4j Simple Logging Facade for Java 简单日志门面,跟 C ...

  6. idea新用法

    https://blog.csdn.net/linsongbin1/article/details/80211919

  7. java编译需要文件后缀名.java 而运行不需要后缀名.class

    对于java源文件HelloWorld.java编译命令:javac HelloWorld.java运行命令:java HelloWorld 编译需要文件后缀名.java 而运行不需要后缀名.clas ...

  8. json格式字符串处理

    public class InternalClass         {             public int MID;             public string Name;     ...

  9. 从Qt谈到C++(一):关键字explicit与隐式类型转换

    转载:果冻虾仁 提出疑问 当我们新建了一个Qt的widgets应用工程时.会自动生成一个框架,包含了几个文件. 其中有个mainwindow.h的头文件.就是你要操纵的UI主界面了.我们看看其中的一段 ...

  10. $(function(){}) ,$(document).ready(function(){}),window.onload = function(){...},$(window).load(function(){...})区别

    1. 写法:      $(function(){}) ,$(document).ready(function(){})是一样的 2. 时间: window.onload和$(window).load ...