SpringMVC源码-DispatcherServlet处理请求概述

请求由Servlet的Service()处理。

FrameworkServlet.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);
	}
}

如果请求方法是patch调用processRequest,否则调用super.service。

HttpServlet.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) {
            // servlet doesn't support if-modified-since, no reason
            // to go through further expensive logic
            doGet(req, resp);
        } else {
            long ifModifiedSince = req.getDateHeader(HEADER_IFMODSINCE);
            if (ifModifiedSince < lastModified) {
                // If the servlet mod time is later, call doGet()
                // Round down to the nearest second for a proper compare
                // A ifModifiedSince of -1 will always be less
                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);
        
    } else if (method.equals(METHOD_OPTIONS)) {
        doOptions(req,resp);
        
    } else if (method.equals(METHOD_TRACE)) {
        doTrace(req,resp);
        
    } else {
        //
        // Note that this means NO servlet supports whatever
        // method was requested, anywhere on this server.
        //

        String errMsg = lStrings.getString("http.method_not_implemented");
        Object[] errArgs = new Object[1];
        errArgs[0] = method;
        errMsg = MessageFormat.format(errMsg, errArgs);
        
        resp.sendError(HttpServletResponse.SC_NOT_IMPLEMENTED, errMsg);
    }
}

如果请求方法是get调用doGet,head方法调用doHead,post方法调用doPost,put方法调用doPut,delete方法调用doDelete,options方法调用doOptions,trace方法调用doTrace,若不是上面的方法则设置错误。

FrameworkServlet.doGet(HttpServletRequest request, HttpServletResponse response)

protected final void doGet(HttpServletRequest request, HttpServletResponse response)
		throws ServletException, IOException {

	processRequest(request, response);
}

HttpServlet.doHead(HttpServletRequest req, HttpServletResponse resp)

   protected void doHead(HttpServletRequest req, HttpServletResponse resp)
    throws ServletException, IOException
{
    NoBodyResponse response = new NoBodyResponse(resp);
    
    doGet(req, response);
    response.setContentLength();
}

head处理方法调用doGet,response设置ContentLength。

FrameworkServlet.doPost(HttpServletRequest request, HttpServletResponse response)

protected final void doPost(HttpServletRequest request, HttpServletResponse response)
		throws ServletException, IOException {

	processRequest(request, response);
}

FrameworkServlet.doPut(HttpServletRequest request, HttpServletResponse response)

protected final void doPut(HttpServletRequest request, HttpServletResponse response)
		throws ServletException, IOException {

	processRequest(request, response);
}

FrameworkServlet.doDelete(HttpServletRequest request, HttpServletResponse response)

protected final void doDelete(HttpServletRequest request, HttpServletResponse response)
		throws ServletException, IOException {

	processRequest(request, response);
}

FrameworkServlet.doOptions(HttpServletRequest request, HttpServletResponse response)

protected void doOptions(HttpServletRequest request, HttpServletResponse response)
		throws ServletException, IOException {

	if (this.dispatchOptionsRequest || CorsUtils.isPreFlightRequest(request)) {
		processRequest(request, response);
		if (response.containsHeader("Allow")) {
			// Proper OPTIONS response coming from a handler - we're done.
			return;
		}
	}

	// Use response wrapper in order to always add PATCH to the allowed methods
	super.doOptions(request, new HttpServletResponseWrapper(response) {
		@Override
		public void setHeader(String name, String value) {
			if ("Allow".equals(name)) {
				value = (StringUtils.hasLength(value) ? value + ", " : "") + HttpMethod.PATCH.name();
			}
			super.setHeader(name, value);
		}
	});
}

如果dispatchOptionsRequest为true或CorsUtils.isPreFlightRequest检查header是否有CROS头部为true,则调用processRequest。super.doOptions设置Allow header。

FrameworkServlet.doTrace(HttpServletRequest request, HttpServletResponse response)

protected void doTrace(HttpServletRequest request, HttpServletResponse response)
		throws ServletException, IOException {

	if (this.dispatchTraceRequest) {
		processRequest(request, response);
		if ("message/http".equals(response.getContentType())) {
			// Proper TRACE response coming from a handler - we're done.
			return;
		}
	}
	super.doTrace(request, response);
}

如果dispatchTraceRequest为true,调用processRequest。super.doTrace设置头部。

FrameworkServlet.dispatchTraceRequest

protected final void processRequest(HttpServletRequest request, HttpServletResponse response)
		throws ServletException, IOException {

	long startTime = System.currentTimeMillis();
	Throwable failureCause = null;

	LocaleContext previousLocaleContext = LocaleContextHolder.getLocaleContext();
	LocaleContext localeContext = buildLocaleContext(request);

	RequestAttributes previousAttributes = RequestContextHolder.getRequestAttributes();
	ServletRequestAttributes requestAttributes = buildRequestAttributes(request, response, previousAttributes);

	WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
	asyncManager.registerCallableInterceptor(FrameworkServlet.class.getName(), new RequestBindingInterceptor());

	initContextHolders(request, localeContext, requestAttributes);

	try {
		doService(request, response);
	}
	catch (ServletException | IOException ex) {
		failureCause = ex;
		throw ex;
	}
	catch (Throwable ex) {
		failureCause = ex;
		throw new NestedServletException("Request processing failed", ex);
	}

	finally {
		resetContextHolders(request, previousLocaleContext, previousAttributes);
		if (requestAttributes != null) {
			requestAttributes.requestCompleted();
		}
		logResult(request, response, failureCause, asyncManager);
		publishRequestHandledEvent(request, response, startTime, failureCause);
	}
}

1、创建LocaleContext
2、创建ServletRequestAttributes请求属性
3、创建WebAsyncManager
4、WebAsyncManager将RequestBindingInterceptor注册到CallableInterceptor。
5、initContextHolders设置请求属性
6、调用doService
7、恢复LocaleContext和ServletRequestAttributes
8、发布ServletRequestHandledEvent事件

DispatcherServlet.doService(HttpServletRequest request, HttpServletResponse response)

protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {
	logRequest(request);

	// 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);
	}

	RequestPath previousRequestPath = null;
	if (this.parseRequestPath) {
		previousRequestPath = (RequestPath) request.getAttribute(ServletRequestPathUtils.PATH_ATTRIBUTE);
		ServletRequestPathUtils.parseAndCache(request);
	}

	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);
			}
		}
		ServletRequestPathUtils.setParsedRequestPath(previousRequestPath, request);
	}
}

1、logRequest返回request的参数字符串供日志打印。
2、对request的属性做快照
3、request设置属性WEB_APPLICATION_CONTEXT_ATTRIBUTE为WebApplicationContext,设置属性LOCALE_RESOLVER_ATTRIBUTE为localeResolver,设置属性THEME_RESOLVER_ATTRIBUTE为themeResolver,设置属性THEME_SOURCE_ATTRIBUTE为ThemeSource。
4、如果flashMapManager不为null,flashMapManager.retrieveAndUpdate保存以前的FlashMap,匹配当前请求的FlashMap并返回,inputFlashMap不为null设置INPUT_FLASH_MAP_ATTRIBUTE为名,inputFlashMap为值的属性。设置OUTPUT_FLASH_MAP_ATTRIBUTE和FLASH_MAP_MANAGER_ATTRIBUTE属性。
5、如果parseRequestPath为true,解析request的PATH_ATTRIBUTE属性值并缓存。
6、doDispatch分发请求进行处理
7、还原request的属性快照

DispatcherServlet.doDispatch(HttpServletRequest request, HttpServletResponse 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 {
			processedRequest = checkMultipart(request);
			multipartRequestParsed = (processedRequest != request);

			// Determine handler for the current request.
			mappedHandler = getHandler(processedRequest);
			if (mappedHandler == null) {
				noHandlerFound(processedRequest, response);
				return;
			}

			// 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();
			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.
			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);
		}
		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);
			}
		}
	}
}

1、WebAsyncUtils.getAsyncManager获取异步web管理器WebAsyncManager
2、checkMultipart检查是否是文件上传请求
3、调用getHandler获取request的handle
4、如果没有当前请求的handle则调用noHandlerFound
5、调用getHandlerAdapter获取handle对应的HandlerAdapter
6、如果请求类型是GET或HEAD则检查请求的lastModified
7、调用mappedHandler.applyPreHandle处理拦截器的前置方法HandlerInterceptor.preHandle,如果为false则退出
8、HandlerAdapter.handle调用Controller层的方法处理请求并返回ModelAndView
9、applyDefaultViewName处理视图名
10、mappedHandler.applyPostHandle处理拦截器的前置方法HandlerInterceptor.postHandle
11、processDispatchResult渲染视图
12、如果是异步web调用mappedHandler.applyAfterConcurrentHandlingStarted否则cleanupMultipart清理文件上传请求

DispatcherServlet.checkMultipart(HttpServletRequest request)

protected HttpServletRequest checkMultipart(HttpServletRequest request) throws MultipartException {
	if (this.multipartResolver != null && this.multipartResolver.isMultipart(request)) {
		if (WebUtils.getNativeRequest(request, MultipartHttpServletRequest.class) != null) {
			if (DispatcherType.REQUEST.equals(request.getDispatcherType())) {
				logger.trace("Request already resolved to MultipartHttpServletRequest, e.g. by MultipartFilter");
			}
		}
		else if (hasMultipartException(request)) {
			logger.debug("Multipart resolution previously failed for current request - " +
					"skipping re-resolution for undisturbed error rendering");
		}
		else {
			try {
				return this.multipartResolver.resolveMultipart(request);
			}
			catch (MultipartException ex) {
				if (request.getAttribute(WebUtils.ERROR_EXCEPTION_ATTRIBUTE) != null) {
					logger.debug("Multipart resolution failed for error dispatch", ex);
					// Keep processing error dispatch with regular request handle below
				}
				else {
					throw ex;
				}
			}
		}
	}
	// If not returned before: return original request.
	return request;
}

如果multipartResolver不为null且multipartResolver.isMultipart判断request是文件上传请求则
1、WebUtils.getNativeRequest判断request是MultipartHttpServletRequest,若是且request.getDispatcherType()是DispatcherType.REQUEST打印日志
2、hasMultipartException判断是否有异常,若有打印日志
3、调用multipartResolver.resolveMultipart解析request并返回

posted @ 2022-11-05 11:51  shigp1  阅读(58)  评论(0编辑  收藏  举报