springMVC源码 (3) DispatcherServlet处理请求

前言

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方法

第九步:处理方法执行后的结果。则其中包括这样几个步骤:

  1. 处理抛出的异常
    当抛出的异常是一个ModelAndViewDefiningException,直接调用其getModelAndView方法获得一个ModelAndView就行了。不是ModelAndViewDefiningException异常时,使用HandlerExceptionResolver来处理异常
  2. 处理View
    首先使用LocaleResolver来处理视图语言。
    然后使用ViewResolver来处理viewName,找到对应的View对象。
    执行View.render方法
  3. 执行interceptor的triggerAfterCompletion方法
原文地址:https://www.cnblogs.com/zhangchenwei/p/12583790.html