DispatcherServlet的doDispatch方法主要用作职责调度工作,本身主要用于控制流程,主要职责如下:

1、文件上传解析,如果请求类型是multipart将通过MultipartResolver进行文件上传解析;

2、通过HandlerMapping,将请求映射到处理器(返回一个HandlerExecutionChain,它包括一个处理器、多个HandlerInterceptor拦截器);

3、通过HandlerAdapter支持多种类型的处理器(HandlerExecutionChain中的处理器);

4、调用HandlerExecutionChain的interceptor和handler

5、解析视图、处理异常,渲染具体的视图等;

    1. 1:doDispatch方法中:如下:

/**
* Process the actual dispatching to the handler. //处理实际调度处理器
* <p>The handler will be obtained by applying the servlet's HandlerMappings in order.    //处理程序将通过按顺序的servlet的处理器映射器获得。
* The HandlerAdapter will be obtained by querying the servlet's installed HandlerAdapters //处理器适配器将通过查询servlet的安装的处理器适配器来获得
* to find the first that supports the handler class.                       //找到支持处理程序类的第一个。
* <p>All HTTP methods are handled by this method. It's up to HandlerAdapters or handlers //所有HTTP方法都由此方法处理。 这取决于处理器适配器或处理程序
* themselves to decide which methods are acceptable.                      //自己决定哪些方法是可以接受的。
* @param request current HTTP request                //请求当前HTTP请求
* @param response current HTTP response               //响应当前的HTTP响应
* @throws Exception in case of any kind of processing failure  //任何类型的处理失败的例外
*/
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {

     HttpServletRequest processedRequest = request;  //processedRequest是经过checkMultipart方法处理过的request请求
HandlerExecutionChain mappedHandler = null;
boolean multipartRequestParsed = false; WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request); try {
ModelAndView mv = null;
Exception dispatchException = null; try {
          //1、文件上传解析,如果请求类型是multipart将通过MultipartResolver进行文件上传解析;  
processedRequest = checkMultipart(request);
multipartRequestParsed = (processedRequest != request);
          //2.通过HandlerMapping,将请求映射到处理器(返回一个HandlerExecutionChain,它包括一个处理器、多个HandlerInterceptor拦截器);
// Determine handler for the current request.   确定当前请求的处理程序。
mappedHandler = getHandler(processedRequest);      //解析第一个方法
if (mappedHandler == null || mappedHandler.getHandler() == null) {
noHandlerFound(processedRequest, response);
return;
}
          //3、通过HandlerAdapter支持多种类型的处理器(HandlerExecutionChain中的处理器);  
// Determine handler adapter for the current request.  确定当前请求的处理程序适配器。
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());    //解析第二个方法 // Process last-modified header, if supported by the handler.  如果处理程序支持,则处理最后修改的头文件。
String method = request.getMethod();    //得到当前的http方法。  
boolean isGet = "GET".equals(method);
if (isGet || "HEAD".equals(method)) {    //处理http的head方法。这种方法应该很少用  
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;
}
}
          //4.1调用HandlerExecutionChain的interceptor  
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}
          //4.2执行解析handler中的args,调用(invoke) controller的方法。得到视图  
// Actually invoke the handler.  实际上调用处理程序。
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());    //解析第三个方法 if (asyncManager.isConcurrentHandlingStarted()) {
return;
}
          //4.3调用HandlerExecutionChain的interceptor  
applyDefaultViewName(processedRequest, mv);
mappedHandler.applyPostHandle(processedRequest, response, mv);
}
catch (Exception ex) {
dispatchException = ex;
}
        //5.解析视图、处理异常  
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);
}
}
}
}

    1.2: DispatcherServlet类中 找到 getHandler

/**
* Return the HandlerExecutionChain for this request.  //返回该请求的处理程序执行链
* <p>Tries all handler mappings in order.        //尝试按顺序处理所有的处理程序映射。
* @param request current HTTP request          //请求当前HTTP请求
* @return the HandlerExecutionChain, or {@code null} if no handler could be found  //处理程序执行链或代码返回null,如果没有找到处理程序
*/
protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
for (HandlerMapping hm : this.handlerMappings) {
if (logger.isTraceEnabled()) {
logger.trace(
"Testing handler map [" + hm + "] in DispatcherServlet with name '" + getServletName() + "'");
}
HandlerExecutionChain handler = hm.getHandler(request);
if (handler != null) {
          //只会调用一个handler进行处理  
return handler;
}
}
return null;
}

    1.3:我们转而去找HandlerMapping的getHander()发现HandlerMapping是一个接口,找到了实现类

/**
* Look up a handler for the given request, falling back to the default  //查找给定请求的处理程序,回到默认值
* handler if no specific one is found.                     //处理程序,如果没有找到特定的。
* @param request current HTTP request                    //请求当前HTTP请求
* @return the corresponding handler instance, or the default handler //相应的处理程序实例或默认处理程序
* @see #getHandlerInternal                          //得到内部处理程序
*/
@Override
public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
     //从实现类中获得处理方法
Object handler = getHandlerInternal(request);
if (handler == null) {
handler = getDefaultHandler();
}
if (handler == null) {
return null;
}
// Bean name or resolved handler?    //Bean名称或解决的处理程序?
if (handler instanceof String) {
String handlerName = (String) handler;
handler = getApplicationContext().getBean(handlerName);
}
     //获得处理程序执行链
HandlerExecutionChain executionChain = getHandlerExecutionChain(handler, request);
if (CorsUtils.isCorsRequest(request)) {
CorsConfiguration globalConfig = this.corsConfigSource.getCorsConfiguration(request);
CorsConfiguration handlerConfig = getCorsConfiguration(handler, request);
CorsConfiguration config = (globalConfig != null ? globalConfig.combine(handlerConfig) : handlerConfig);
executionChain = getCorsHandlerExecutionChain(request, executionChain, config);
}
return executionChain;
}

    1.4:

/**
* Build a {@link HandlerExecutionChain} for the given handler, including     //为给定的处理程序构建一个链接处理程序执行链,包括
* applicable interceptors.                                 //适用拦截器。
* <p>The default implementation builds a standard {@link HandlerExecutionChain} //默认实现构建一个标准的链接处理程序执行链
* with the given handler, the handler mapping's common interceptors, and any  //与给定的处理程序,处理程序映射的常见拦截器和任何
* {@link MappedInterceptor}s matching to the current request URL. Interceptors //映射映射拦截器与当前请求URL匹配。拦截器
* are added in the order they were registered. Subclasses may override this   //按照注册顺序添加。 子类可以覆盖此
* in order to extend/rearrange the list of interceptors.               //以便扩展/重新排列拦截器列表。
* <p><b>NOTE:</b> The passed-in handler object may be a raw handler or a     //注意:传入处理程序对象可能是原始处理程序或
* pre-built {@link HandlerExecutionChain}. This method should handle those    //预制链接处理程序执行链。 这种方法应该处理那些
* two cases explicitly, either building a new {@link HandlerExecutionChain}   //建立一个新的链接处理程序执行链
* or extending the existing chain.                            //或扩展现有的链。
* <p>For simply adding an interceptor in a custom subclass, consider calling   //为了简单地在自定义子类中添加拦截器,请考虑调用
* {@code super.getHandlerExecutionChain(handler, request)} and invoking      //代码:得到父类处理程序执行链(处理器,请求)}并调用
* {@link HandlerExecutionChain#addInterceptor} on the returned chain object.   //{@链接处理程序执行链、添加拦截器}在返回的链对象上。
* @param handler the resolved handler instance (never {@code null})        //处理程序解析的处理程序实例(代码从不为空)
* @param request current HTTP request                          //请求当前HTTP请求
* @return the HandlerExecutionChain (never {@code null})              //处理程序执行链(代码从不为空)
* @see #getAdaptedInterceptors()                            //获得适应的拦截器
*/
protected HandlerExecutionChain getHandlerExecutionChain(Object handler, HttpServletRequest request) {
//如果没有获得则创建一个
     HandlerExecutionChain chain = (handler instanceof HandlerExecutionChain ?
(HandlerExecutionChain) handler : new HandlerExecutionChain(handler));
     //获得IP地址及端口后的URL地址
String lookupPath = this.urlPathHelper.getLookupPathForRequest(request);

     //在HandlerExecutionChain中添加拦截器
     // 遍历 SpringMVC 容器的所有拦截器
     for (HandlerInterceptor interceptor : this.adaptedInterceptors) {
       // 判断拦截器类型,属于 MappedInterceptor,则先匹配路径,否则直接添加
if (interceptor instanceof MappedInterceptor) {
MappedInterceptor mappedInterceptor = (MappedInterceptor) interceptor;

          //根据lookupPath来获取Interceptor
          if (mappedInterceptor.matches(lookupPath, this.pathMatcher)) {
chain.addInterceptor(mappedInterceptor.getInterceptor());
}
}
else {
chain.addInterceptor(interceptor);
}
}
return chain;
}

    结论:处理器执行链=1个hanlder+N个Interceptor

    2.1:HandlerAdaptor执行流程(进入方法在1.1)

/**
* Return the HandlerAdapter for this handler object.      //返回:该处理程序对象的处理程序适配器。
* @param handler the handler object to find an adapter for  //传入的参数:处理处理程序对象以找到适配器
* @throws ServletException if no HandlerAdapter can be found for the handler. This is a fatal error.  
*/    //抛出的异常:如果找不到处理程序适配器,则Servlet异常。这是一个致命错误。
protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
     //遍历所有的handlerAdapters
for (HandlerAdapter ha : this.handlerAdapters) {
if (logger.isTraceEnabled()) {
logger.trace("Testing handler adapter [" + ha + "]");
}
       //调用相应实现的support方法,排在最前面的优先调用
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.1:在这里发现了一个接口,找到它 的实现(进入方法在1.1)

/**
* Use the given handler to handle this request.    //使用给定的处理程序来处理此请求。
* The workflow that is required may vary widely.    //所需的工作流程可能会有很大差异。
* @param request current HTTP request           //请求当前HTTP请求
* @param response current HTTP response          //响应当前的HTTP响应
* @param handler handler to use. This object must have previously been passed  //处理程序处理程序使用 此对象必须先前已被传递
* to the {@code supports} method of this interface, which must have        //到这个接口的{@code支持}方法,它必须具有
* returned {@code true}.                                  //已返回{@code true}。
* @throws Exception in case of errors                          //异常情况下出错
* @return ModelAndView object with the name of the view and the required     //ModelAndView对象具有视图的名称和必需
* model data, or {@code null} if the request has been handled directly      //模型数据,或{@code null},如果请求已被直接处理
*/
ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception;

    3.2接口的各个实现

    3.3这里我们用的是SimpleControllerHandlerAdapter

public class SimpleControllerHandlerAdapter implements HandlerAdapter {
@Override
public boolean supports(Object handler) {
     //判断是否是Controller类  
return (handler instanceof Controller);
}
   //执行Controller的handleRequest方法  
@Override
public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
      //本质是执行Controller的handleRequest方法  
return ((Controller) handler).handleRequest(request, response);
}
@Override
public long getLastModified(HttpServletRequest request, Object handler) {
if (handler instanceof LastModified) {
return ((LastModified) handler).getLastModified(request);
}
return -1L;
}
}

springmvc的DispatcherServlet源码——doDispatch方法解析的更多相关文章

  1. HashMap源码__tableSizeFor方法解析

    tableSizeFor(int cap)方法返回不小于指定参数cap的最小2的整数次幂,具体是怎么实现的呢?看源码! /** * Returns a power of two size for th ...

  2. springmvc(1)DispatcherServlet源码简单解析

    springmvc的简单配置 1.首先需要在web.xml中配置DispatcherServlet,这个类是springmvc的核心类,所以的操作都是由这里开始,并且大部分都是在这里面实现的,比如各种 ...

  3. 小白文-SpringMVC-解读DispatcherServlet源码

    SpringMVC 学习完Spring框架技术之后,差不多会出现两批人: 一批是听得云里雾里,依然不明白这个东西是干嘛的: 还有一批就是差不多理解了核心思想,但是不知道这些东西该如何去发挥它的作用. ...

  4. 框架源码系列五:学习源码的方法(学习源码的目的、 学习源码的方法、Eclipse里面查看源码的常用快捷键和方法)

    一. 学习源码的目的 1. 为了扩展和调优:掌握框架的工作流程和原理 2. 为了提升自己的编程技能:学习他人的设计思想.编程技巧 二. 学习源码的方法 方法一: 1)掌握研究的对象和研究对象的核心概念 ...

  5. MyBatis 源码分析 - 配置文件解析过程

    * 本文速览 由于本篇文章篇幅比较大,所以这里拿出一节对本文进行快速概括.本篇文章对 MyBatis 配置文件中常用配置的解析过程进行了较为详细的介绍和分析,包括但不限于settings,typeAl ...

  6. InfluxDB源码目录结构解析

    操作系统 : CentOS7.3.1611_x64 go语言版本:1.8.3 linux/amd64 InfluxDB版本:1.1.0 influxdata主目录结构 [root@localhost ...

  7. 查看xml源码的方法

    查看xml源码的方法 要通过查看源码才能看到xml源码 因为 print_r输出的时候 默认页面打开是html编码的...... 所以解析不了xml

  8. Spring源码入门——DefaultBeanNameGenerator解析 转发 https://www.cnblogs.com/jason0529/p/5272265.html

    Spring源码入门——DefaultBeanNameGenerator解析   我们知道在spring中每个bean都要有一个id或者name标示每个唯一的bean,在xml中定义一个bean可以指 ...

  9. ArrayList 源码底层实现解析 基于1.8

    ArrayList 介绍 ArrayList是一种线性数据结构,它的底层是用数组实现的,是动态数组.与Java中的数组相比,它的容量能动态增长.源代码里有解释.当创建一个数组的时候,就必须确定它的大小 ...

随机推荐

  1. 媒体格式分析之flv -- 基于FFMPEG

    本来是应该先写一个媒体文件格式的简单讲解的,还没来得及写,以后再写.今天就先根据ffmpeg的flv.c的flv_demux这个结构体来讲解一下当前比较流行的媒体格式flv. FLV 是FLASH V ...

  2. requirejs的打包工具r.js

    不建议用命令行,还是用配置文件比较方便--build.js. 我的build.js文件内容大概如下: ( { appDir : './', baseUrl : './scripts', dir : ' ...

  3. TI官网常用链接

    TMS320C6000系列DSP库dsplib下载 TMS320C6000系列DSP库imglib下载 TMS320C6000系列DSP库mathlib下载 TMS320C66657技术文档

  4. window下redis如何查看版本号

    1.启动服务端:redis-server 2.启动客户端:redis-cli 3.客户端输入:info 即可.

  5. [poj2955/nyoj15]括号匹配(区间dp)

    解题关键:了解转移方程即可. 转移方程:$dp[l][r] = dp[l + 1][r - 1] + 2$ 若该区间左右端点成功匹配.然后对区间内的子区间取max即可. nyoj15:求需要添加的最少 ...

  6. Oracle数据去重

    一.完全重复数据去重方法    具体思路是,首先创建一个临时表,然后将DISTINCT之后的表数据插入到这个临时表中;然后清空原表数据;再讲临时表中的数据插入到原表中;最后删除临时表. 对于表中完全重 ...

  7. 条款29:为“异常安全”而努力是值得的

    当异常被抛出时,带有异常安全性的函数: 1.不泄露任何资源 2.不允许数据败坏   异常安全函数提供以下三个保证之一: 1.基本承诺:如果异常被抛出,程序内的任何事物仍然保持在有效的状态下.没有任何对 ...

  8. CPU密集型和IO密集型

    对于Python如果是CPU密集型应该用多进程模型(大量的计算)   如果是IO密集型应该用多线程模型(数据的读取写入.网络IO数据传输) 由于GIL的存在,CPython不能有效的利用多核处理器,表 ...

  9. 7.10实习培训日志-markdown Git

    父模块github地址 一. markdown 1. markdown列表 html是一种发布的格式,markdown是一种书写的格式 区块引用 列表 图片 表格 html 标题 记笔记 写博客 2. ...

  10. C#——传值参数(3)

    上篇文章我与大家共同学习了 值参数——引用类型这次与大家共同学习 传值参数--引用类型,不创建新对象,只操作对象这是个思维导图:我们仍需记住:1.值参数创建变量的副本 2.对值参数的改变不会影响变量的 ...