天天看点

Http请求处理流程源码解析

作者:路过一排树

http请求流程

http请求的处理过程大致为:

Http请求处理流程源码解析

那么服务器端web应用程序是如何进行处理的呢?下面让我们一起探索其中的原理,以下是一些个人理解,欢迎大家讨论和交流

  1.Tomcat是Web应用服务器,是一种Servlet/JSP容器,因此,所有的请求都会从DispatcherServlet进行处理,首先请求会到达`doService`方法,该方法会调用doDispatch处理实际的请求。

@Override
	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;
        // 确定给定的请求是否是包含请求,即不是来自外部的顶级HTTP请求。
		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());
		// 放入LocaleResolver,作用是解析Request中的语言标志参数或head中的Accept-Language参数,并将解析的结果保存到指定的域中,此处放入的是AcceptHeaderLocaleResolver
        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);
				}
			}
			if (this.parseRequestPath) {
				ServletRequestPathUtils.setParsedRequestPath(previousRequestPath, request);
			}
		}
	}           

  2.doDispatch方法,先尝试获取处理当前请求的请求处理链,如果没有获取,则抛出异常;否则,执行请求处理链,ConversionServiceExposingInterceptor->ResourceUrlProviderExposingInterceptor

此处

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.
                // 获取处理请求的适配器,RequestMappingHandlerAdapter
				HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());

				// Process last-modified header, if supported by the handler.
				String method = request.getMethod();
				boolean isGet = HttpMethod.GET.matches(method);
				if (isGet || HttpMethod.HEAD.matches(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.
                // 执行请求处理,调用AbstractHandlerMethodAdapter类中的handle方法
				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 ServletException("Handler dispatch failed: " + err, err);
			}
			// 处理modelAndView,如果出现异常,则处理异常,抛出;否则,反向执行请求处理链中的afterCompletion方法
			processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
		}
		catch (Exception ex) {
			triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
		}
		catch (Throwable err) {
			triggerAfterCompletion(processedRequest, response, mappedHandler,
					new ServletException("Handler processing failed: " + err, 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);
				}
			}
		}
	}           

  3.AbstractHandlerMethodAdapter#handleInternal方法。handle方法会调用内部的handleInternal方法

protected ModelAndView handleInternal(HttpServletRequest request,
			HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {

		ModelAndView mav;
        // 校验请求类型和会话是否合法,如果没有设定,则不校验
		checkRequest(request);

		// Execute invokeHandlerMethod in synchronized block if required.
		if (this.synchronizeOnSession) {  // 同步阻塞请求
			HttpSession session = request.getSession(false);
			if (session != null) {
				Object mutex = WebUtils.getSessionMutex(session);
				synchronized (mutex) {
					mav = invokeHandlerMethod(request, response, handlerMethod);
				}
			}
			else {
				// No HttpSession available -> no mutex necessary
				mav = invokeHandlerMethod(request, response, handlerMethod);
			}
		}
		else {
			// No synchronization on session demanded at all...
            // 非同步阻塞请求,实际调用此处
			mav = invokeHandlerMethod(request, response, handlerMethod);
		}

		if (!response.containsHeader(HEADER_CACHE_CONTROL)) {
			if (getSessionAttributesHandler(handlerMethod).hasSessionAttributes()) {
				applyCacheSeconds(response, this.cacheSecondsForSessionAttributeHandlers);
			}
			else {
				// 对响应内容进行预处理
				prepareResponse(response);
			}
		}

		return mav;
	}           

  4.调用ServletInvocableHandlerMethod#invokeHandlerMethod方法

protected ModelAndView invokeHandlerMethod(HttpServletRequest request,
			HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
        // 封装请求
		ServletWebRequest webRequest = new ServletWebRequest(request, response);
        // 数据绑定工厂  用于请求参数与controller的参数(实体类)类型和参数转换
		WebDataBinderFactory binderFactory = getDataBinderFactory(handlerMethod);
		ModelFactory modelFactory = getModelFactory(handlerMethod, binderFactory);

		ServletInvocableHandlerMethod invocableMethod = createInvocableHandlerMethod(handlerMethod);
		// 设置请求参数解析器,默认有27个
		if (this.argumentResolvers != null) {
			invocableMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers);
		}
		// 设置返回值处理器,默认15个
		if (this.returnValueHandlers != null) {
			invocableMethod.setHandlerMethodReturnValueHandlers(this.returnValueHandlers);
		}
		invocableMethod.setDataBinderFactory(binderFactory);
		// 设置参数名称解析器
		invocableMethod.setParameterNameDiscoverer(this.parameterNameDiscoverer);

		ModelAndViewContainer mavContainer = new ModelAndViewContainer();
		// 获取请求重定向前的参数  DispatcherServlet#doService方法中设置的
		mavContainer.addAllAttributes(RequestContextUtils.getInputFlashMap(request));
		modelFactory.initModel(webRequest, mavContainer, invocableMethod);
		// 设置默认模型不允许在重定向场景中使用
		mavContainer.setIgnoreDefaultModelOnRedirect(this.ignoreDefaultModelOnRedirect);

		AsyncWebRequest asyncWebRequest = WebAsyncUtils.createAsyncWebRequest(request, response);
		asyncWebRequest.setTimeout(this.asyncRequestTimeout);

		WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
		asyncManager.setTaskExecutor(this.taskExecutor);
		asyncManager.setAsyncWebRequest(asyncWebRequest);
		asyncManager.registerCallableInterceptors(this.callableInterceptors);
		asyncManager.registerDeferredResultInterceptors(this.deferredResultInterceptors);

		if (asyncManager.hasConcurrentResult()) {
			Object result = asyncManager.getConcurrentResult();
			mavContainer = (ModelAndViewContainer) asyncManager.getConcurrentResultContext()[0];
			asyncManager.clearConcurrentResult();
			LogFormatUtils.traceDebug(logger, traceOn -> {
				String formatted = LogFormatUtils.formatValue(result, !traceOn);
				return "Resume with async result [" + formatted + "]";
			});
			invocableMethod = invocableMethod.wrapConcurrentResult(result);
		}
		// 调用目标方法进行业务逻辑处理,并对返回值进行处理
		invocableMethod.invokeAndHandle(webRequest, mavContainer);
		if (asyncManager.isConcurrentHandlingStarted()) {
			return null;
		}
		// 返回结果  invocableMethod.invokeAndHandle方法中标记了请求处理完成
		return getModelAndView(mavContainer, modelFactory, webRequest);
	}           

  5.ServletInvocableHandlerMethod#invokeAndHandle方法,该方法完成业务方法的调用,以及对业务方法返回结果的处理

public void invokeAndHandle(ServletWebRequest webRequest, ModelAndViewContainer mavContainer,
			Object... providedArgs) throws Exception {
		// 调用业务方法,并返回执行结果
		Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs);
		setResponseStatus(webRequest);

		if (returnValue == null) {
			if (isRequestNotModified(webRequest) || getResponseStatus() != null || mavContainer.isRequestHandled()) {
				disableContentCachingIfNecessary(webRequest);
				mavContainer.setRequestHandled(true);
				return;
			}
		}
		else if (StringUtils.hasText(getResponseStatusReason())) {
			mavContainer.setRequestHandled(true);
			return;
		}

		mavContainer.setRequestHandled(false);
		Assert.state(this.returnValueHandlers != null, "No return value handlers");
		try {
			// 对业务方法的返回结果进行处理
			this.returnValueHandlers.handleReturnValue(
					returnValue, getReturnValueType(returnValue), mavContainer, webRequest);
		}
		catch (Exception ex) {
			if (logger.isTraceEnabled()) {
				logger.trace(formatErrorForReturnValue(returnValue), ex);
			}
			throw ex;
		}
	}           

  6.调用ServletInvocableHandlerMethod#invokeAndHandle方法,该方法中会调用invokeForRequest方法,此方法中调用doInvoke方法,最终完成业务方法调用,并将业务方法的执行结果返回

public Object invokeForRequest(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer,
			Object... providedArgs) throws Exception {
		// 参数解析
		Object[] args = getMethodArgumentValues(request, mavContainer, providedArgs);
		if (logger.isTraceEnabled()) {
			logger.trace("Arguments: " + Arrays.toString(args));
		}
		// 调用业务方法
		return doInvoke(args);
	}           

  7.调用HandlerMethodReturnValueHandlerComposite#handleReturnValue对返回结果进行处理,该方法中会调用RequestResponseBodyMethodProcessor#handleReturnValue方法处理结果(controller层方法标注有@ResponseBody注解的方法)

public void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType,
			ModelAndViewContainer mavContainer, NativeWebRequest webRequest)
			throws IOException, HttpMediaTypeNotAcceptableException, HttpMessageNotWritableException {
		// 设置标记,说明请求已经处理完成
		mavContainer.setRequestHandled(true);
		ServletServerHttpRequest inputMessage = createInputMessage(webRequest);
		ServletServerHttpResponse outputMessage = createOutputMessage(webRequest);

		if (returnValue instanceof ProblemDetail detail) {
			outputMessage.setStatusCode(HttpStatusCode.valueOf(detail.getStatus()));
			if (detail.getInstance() == null) {
				URI path = URI.create(inputMessage.getServletRequest().getRequestURI());
				detail.setInstance(path);
			}
		}

		// Try even with null return value. ResponseBodyAdvice could get involved.
		// 此处完成业务方法返回值->响应体内容的转换,也是实现自已返回格式的输出位置
		writeWithMessageConverters(returnValue, returnType, inputMessage, outputMessage);
	}           

  8.上述方法执行完成后,返回到RequestMappingHandlerAdapter#handleInternal方法

.....
	else {
			// No synchronization on session demanded at all...
			// 非同步阻塞请求,实际调用此处
			mav = invokeHandlerMethod(request, response, handlerMethod);
		}

		if (!response.containsHeader(HEADER_CACHE_CONTROL)) {
			if (getSessionAttributesHandler(handlerMethod).hasSessionAttributes()) {
				applyCacheSeconds(response, this.cacheSecondsForSessionAttributeHandlers);
			}
			else {
				// 对响应内容进行预处理,如对响应内容设置缓存时间等,缓存有效期内,浏览器不会在发起请求
				prepareResponse(response);
			}
		}

	return mav;           

  8.返回到DispatcherServlet#doServlet方法,执行完ha.handle调用后。首先,执行请求处理链中的postHandle方法,然后执行processDispatchResult检测是否发生异常,没有异常,则反向执行请求链中的afterCompletion方法(默认方法空,没有实际的逻辑),到此doDispatch方法分析完成。

protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
            ......
				// Actually invoke the handler.
                // 执行请求处理,调用AbstractHandlerMethodAdapter类中的handle方法
				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 ServletException("Handler dispatch failed: " + err, err);
			}
			// 处理modelAndView,如果出现异常,则处理异常,抛出;否则,反向执行请求处理链中的afterCompletion方法
			processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
		}
		catch (Exception ex) {
			triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
		}
		catch (Throwable err) {
			triggerAfterCompletion(processedRequest, response, mappedHandler,
					new ServletException("Handler processing failed: " + err, 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);
				}
			}
		}
	}           

继续阅读