Spring MVC学习笔记(三) -SpringMVC源码分析之DispatcherServlet

Scroll Down

Spring MVC中源码分析-DispatcherServlet

DispatcherServlet的继承结构

前面说了DispatcerServlet是SpringMVC最重要类之一了,其实DispatcherServlet也是一个Servlet,所以这里首先看看DispatcherServlet的继承结构

![image-20200524115201099](D:\文档资料\拉勾训练营\笔记\第一阶段\spring MVC\images\image-20200524115201099.png)

从上图可以看到,doGet/doPost是交由父类FrameworkServlet来进行处理的,然后再调用最终的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 检查是否是⽂件上传的请求
                processedRequest = checkMultipart(request);
                multipartRequestParsed = (processedRequest != request);
// Determine handler for the current request.
/*
2 取得处理当前请求的Controller,这⾥也称为Handler,即处理器
这⾥并不是直接返回 Controller,⽽是返回 HandlerExecutionChain 请求处
理链对象
该对象封装了Handler和Inteceptor
*/
                mappedHandler = getHandler(processedRequest);
                if (mappedHandler == null) {
// 如果 handler 为空,则返回404
                    noHandlerFound(processedRequest, response);
                    return;
                }
// Determine handler adapter for the current request.
// 3 获取处理请求的处理器适配器 HandlerAdapter
                HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
// Process last-modified header, if supported by the handler.
// 处理 last-modified 请求头
                String method = request.getMethod();
                boolean isGet = "GET".equals(method);
                if (isGet || "HEAD".equals(method)) {
                    long lastModified = ha.getLastModified(request,
                            mappedHandler.getHandler());
                    if (new ServletWebRequest(request,
                            response).checkNotModified(lastModified) && isGet) {
                        return;
                    }
                }
                if (!mappedHandler.applyPreHandle(processedRequest, response)) {
                    return;
                }
// Actually invoke the handler.
// 4 实际处理器处理请求,返回结果视图对象
                mv = ha.handle(processedRequest, response,
                        mappedHandler.getHandler());
                if (asyncManager.isConcurrentHandlingStarted()) {
                    return;
                }
// 结果视图对象的处理
                applyDefaultViewName(processedRequest, mv);
                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);
            }
// 5 跳转⻚⾯,渲染视图
            processDispatchResult(processedRequest, response, mappedHandler, mv,
                    dispatchException);
        } catch (Exception ex) {
//最终会调⽤HandlerInterceptor的afterCompletion ⽅法
            triggerAfterCompletion(processedRequest, response, mappedHandler,
                    ex);
        } catch (Throwable err) {
//最终会调⽤HandlerInterceptor的afterCompletion ⽅法
            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);
                }
            }
        }
    }

第1步-判断是否是上传文件请求

	protected HttpServletRequest checkMultipart(HttpServletRequest request) throws MultipartException {
        //配置上传文件解析器并且请求类型是multipart/开头的,则为上传文件
		if (this.multipartResolver != null && this.multipartResolver.isMultipart(request)) {
        }
    }
	@Override
	public boolean isMultipart(HttpServletRequest request) {
		return StringUtils.startsWithIgnoreCase(request.getContentType(), "multipart/");
	}

第2步-获取具体的HandlerExecutionChain

取得处理当前请求的Controller,这⾥也称为Handler,即处理器,这⾥并不是直接返回 Controller,⽽是返回 HandlerExecutionChain 请求处理链对象,该对象封装了Handler和Inteceptor

![image-20200524120603234](D:\文档资料\拉勾训练营\笔记\第一阶段\spring MVC\images\image-20200524120603234.png)

getHandler这里我们用注解写的,这里就是使用RequestMappingHandlerMapping进行解析的,通过URL连接前往初始化时根据注解中url缓存起来的handlerMethod

![image-20200524121502202](D:\文档资料\拉勾训练营\笔记\第一阶段\spring MVC\images\image-20200524121502202.png)

	public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
		Object handler = getHandlerInternal(request);
	//..

		HandlerExecutionChain executionChain = getHandlerExecutionChain(handler, request);
//..
	

		return executionChain;
	}

这里通过 getHandlerExecutionChain方法获取HandlerExecutionChain的处理链,这里主要是将所有符合的拦截器加入到对应的拦截链中

	protected HandlerExecutionChain getHandlerExecutionChain(Object handler, HttpServletRequest request) {
		HandlerExecutionChain chain = (handler instanceof HandlerExecutionChain ?
				(HandlerExecutionChain) handler : new HandlerExecutionChain(handler));

		String lookupPath = this.urlPathHelper.getLookupPathForRequest(request);
		for (HandlerInterceptor interceptor : this.adaptedInterceptors) {
			if (interceptor instanceof MappedInterceptor) {
				MappedInterceptor mappedInterceptor = (MappedInterceptor) interceptor;
                //判断拦截器是否符合对应请求,是的话,加入到拦截链中
				if (mappedInterceptor.matches(lookupPath, this.pathMatcher)) {
					chain.addInterceptor(mappedInterceptor.getInterceptor());
				}
			}
			else {
				chain.addInterceptor(interceptor);
			}
		}
		return chain;
	}

第3步-获取处理请求的处理器适配器 HandlerAdapter

这里是使用适配器模式找到相匹配的适配器

![image-20200524122321677](D:\文档资料\拉勾训练营\笔记\第一阶段\spring MVC\images\image-20200524122321677.png)

这里三种适配器是针对我们使用不同的方法创建的Controller来匹配的,原理都是一样的,使用适配器模式,找到匹配的适配器,通过适配器再调用具体的方法

三个适配器都实现了HandlerAdapter接口,这里看一下HandlerAdapter

public interface HandlerAdapter {

	/**
	 * Given a handler instance, return whether or not this {@code HandlerAdapter}
	 * can support it. Typical HandlerAdapters will base the decision on the handler
	 * type. HandlerAdapters will usually only support one handler type each.
	 * <p>A typical implementation:
	 * <p>{@code
	 * return (handler instanceof MyHandler);
	 * }
	 * @param handler handler object to check
	 * @return whether or not this object can use the given handler
	 */
	boolean supports(Object handler);

	/**
	 * Use the given handler to handle this request.
	 * The workflow that is required may vary widely.
	 * @param request current HTTP request
	 * @param response current HTTP response
	 * @param handler handler to use. This object must have previously been passed
	 * to the {@code supports} method of this interface, which must have
	 * returned {@code true}.
	 * @throws Exception in case of errors
	 * @return a ModelAndView object with the name of the view and the required
	 * model data, or {@code null} if the request has been handled directly
	 */
	@Nullable
	ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception;

	/**
	 * Same contract as for HttpServlet's {@code getLastModified} method.
	 * Can simply return -1 if there's no support in the handler class.
	 * @param request current HTTP request
	 * @param handler handler to use
	 * @return the lastModified value for the given handler
	 * @see javax.servlet.http.HttpServlet#getLastModified
	 * @see org.springframework.web.servlet.mvc.LastModified#getLastModified
	 */
	long getLastModified(HttpServletRequest request, Object handler);

}

使用supports方法判断是否是符合的适配器,使用handle调用最终的需要调用的方法

第4步实际处理器处理请求,返回结果视图对象

使用上面获得到的HandlerAdapter反射进行调用具体的handler方法,获得最终返回的视图对象,

![image-20200524130240542](D:\文档资料\拉勾训练营\笔记\第一阶段\spring MVC\images\image-20200524130240542.png)

![image-20200524130257020](D:\文档资料\拉勾训练营\笔记\第一阶段\spring MVC\images\image-20200524130257020.png)

![image-20200524130308056](D:\文档资料\拉勾训练营\笔记\第一阶段\spring MVC\images\image-20200524130308056.png)

![image-20200524130333711](D:\文档资料\拉勾训练营\笔记\第一阶段\spring MVC\images\image-20200524130333711.png)

![image-20200524130314583](D:\文档资料\拉勾训练营\笔记\第一阶段\spring MVC\images\image-20200524130314583.png)

第5步 processDispatchResult方法跳转⻚⾯,渲染视图

  • render⽅法完成渲染

![image-20200524130426862](D:\文档资料\拉勾训练营\笔记\第一阶段\spring MVC\images\image-20200524130426862.png)

  • 视图解析器解析出View视图对象

![image-20200524130435123](D:\文档资料\拉勾训练营\笔记\第一阶段\spring MVC\images\image-20200524130435123.png)

  • 在解析出View视图对象的过程中会判断是否重定向、是否转发等,不同的情况封装的是不同的View实现

![image-20200524130501902](D:\文档资料\拉勾训练营\笔记\第一阶段\spring MVC\images\image-20200524130501902.png)

  • 解析出View视图对象的过程中,要将逻辑视图名解析为物理视图名

![image-20200524130530720](D:\文档资料\拉勾训练营\笔记\第一阶段\spring MVC\images\image-20200524130530720.png)

  • 封装View视图对象之后,调⽤了view对象的render⽅法

![image-20200524130545130](D:\文档资料\拉勾训练营\笔记\第一阶段\spring MVC\images\image-20200524130545130.png)

  • 渲染数据

![image-20200524130556513](D:\文档资料\拉勾训练营\笔记\第一阶段\spring MVC\images\image-20200524130556513.png)

  • 把modelMap中的数据暴露到request域中,这也是为什么后台model.add之后在jsp中可以从请求
    域取出来的根本原因

![image-20200524130611348](D:\文档资料\拉勾训练营\笔记\第一阶段\spring MVC\images\image-20200524130611348.png)

  • 将数据设置到请求域中

![image-20200524130624222](D:\文档资料\拉勾训练营\笔记\第一阶段\spring MVC\images\image-20200524130624222.png)