Spring原码解析—SpringMVC请求处理流程

我们都知道SpringMVC的核心就是DispatcherServlet,它负责接收请求和调度,在开始原码解析前先来看看SpringMVC请求的一个处理流程图:

1)客户端发送请求,DispatcherServlet接收请求

2)DispatcherServlet将请求交给DefaultAnnotationHandlerMapping找到对应的映射方法

3)通过对应的DefaultAnnotationHandlerAdapter  invoke特定的方法

4)调用自己的Controller和相应的方法,给Model设置数据和返回视图

5)DefaultAnnotationHandlerAdapter组装ModelAndView并返回给DispatcherServlet

6)通过InternalResourceViewResolver解析

7)响应客户端


对请求流程有了一个初步的了解后,接下来我们开始原码分析:

确定请求入口:

因为DispatcherServlet本质上是一个Servlet所有它一定有doPost()和doGet()方法,而DispatcherServlet又继承FrameworkServlet,通过分析我们在FrameworkServlet中找到请求处理方法,如图:

而doPost()和doGet()方法又会调用pocessRequest()这个方法,如图:

            

因此我们在processRequest这个方法上打上断点。

接下来开启debug并发送请求,来到断点处processRequest方法,其原码如下:


	//处理请求
	protected final void processRequest(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {

		long startTime = System.currentTimeMillis();
		Throwable failureCause = null;
		//获取LocaleContextHolder中原来保存的LocaleContext
		//刚开始一般是null
		LocaleContext previousLocaleContext = LocaleContextHolder.getLocaleContext();
		//获取当前请求的LocaleContext
		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());
   //将当前请求的LocaleContext和ServletRequestAttributes设置到LocaleContextHolder和RequestContextHolder中
		initContextHolders(request, localeContext, requestAttributes);

		try {

			//前面都可以不太了解,重点是这个方法,执行完前面的操作后,会将请求统一交给这个方法处理逻辑
			doService(request, response);
		}
		catch (ServletException ex) {
			failureCause = ex;
			throw ex;
		}
		catch (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();
				//这里执行了request后有一个requestActive状态值会转变为false,执行前是true

			}

			if (logger.isDebugEnabled()) {
				if (failureCause != null) {
					this.logger.debug("Could not complete request", failureCause);
				}
				else {
					if (asyncManager.isConcurrentHandlingStarted()) {
						logger.debug("Leaving response open for concurrent processing");
					}
					else {
						this.logger.debug("Successfully completed request");
					}
				}
			}
 			//发布ServletRequestHandlerEvent消息,这个请求是否执行成功都会发布消息的
			publishRequestHandledEvent(request, response, startTime, failureCause);
		}
	}

我们在来看一下doService这个方法,这个方法被DispatcherServlet覆写了,所有调用的是DispatcherServlet的实现:


DispatcherServlet.java

		@Override
	protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {
		if (logger.isDebugEnabled()) {
			String resumed = WebAsyncUtils.getAsyncManager(request).hasConcurrentResult() ? " resumed" : "";
			logger.debug("DispatcherServlet with name '" + getServletName() + "'" + resumed +
					" processing " + request.getMethod() + " request for [" + getRequestUri(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<String, Object>();
			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());

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

在看原码的时候,我们首先不应该关注太多的细节,而应掌握它的主要流程。

我们接着看一下doDispatch()这个方法:

DispatcherServlet.java

	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.
				//通过我们请求的路径 拿到需要访问的自定义的Controller里的指定的方法	包含请求和拦截器
				mappedHandler = getHandler(processedRequest);  //-----》HandlerExecutionChain -》mappedHandler
				if (mappedHandler == null || mappedHandler.getHandler() == null) {
					noHandlerFound(processedRequest, response);
					return;
				}

				// Determine handler adapter for the current request.
				//通过handler拿到对应的handlerAdapter  我们这里是RequestMappingHandlerAdapter
				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 (logger.isDebugEnabled()) {
						logger.debug("Last-Modified value for [" + getRequestUri(request) + "] is: " + lastModified);
					}
					if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
						return;
					}
				}

				if (!mappedHandler.applyPreHandle(processedRequest, response)) {
					return;
				}

				// Actually invoke the handler.
				//通过反射调用 我们那个方法  并通过RequestMappingHandlerAdapter组装ModelAndView 也就是将return的String与Model组装
				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);
				}
			}
		}
	}

在执行完processDispatchResult后就差不多完成了我们的流程

我们看一下这个方法:

最后在看一下publishRequestHandledEvent这个事件发布方法的内容。

private void publishRequestHandledEvent(
	HttpServletRequest request, HttpServletResponse response, long startTime, Throwable failureCause) {

	if (this.publishEvents) {
		// Whether or not we succeeded, publish an event.
		long processingTime = System.currentTimeMillis() - startTime;
		int statusCode = (responseGetStatusAvailable ? response.getStatus() : -1);
		this.webApplicationContext.publishEvent(
				new ServletRequestHandledEvent(this,
						request.getRequestURI(), request.getRemoteAddr(),
						request.getMethod(), getServletConfig().getServletName(),
						WebUtils.getSessionId(request), getUsernameForRequest(request),
						processingTime, failureCause, statusCode));
	}
}

在publishRequestHandledEvent方法执行后,如果有自定义实现ApplicationListener,那么就会调用里面的onApplicationEvent方法,如图:

import org.springframework.web.context.support.ServletRequestHandledEvent;

@Component
public class ServletReqestHandledEventListener implements ApplicationListener<ServletRequestHandledEvent> {
    final static Logger logger = LoggerFactory.getLogger("SRHEServlet");

    @Override
    public void onApplicationEvent(ServletRequestHandledEvent servletRequestHandledEvent) {
        logger.info(servletRequestHandledEvent.getDescription()+"自定义ApplicationListener");
    }
}

当请求结束后,控制台打印:

它可以用来记录日志,并且只需要把自己需要做的事情写到onApplicationEvent里面就可以了。

总结:processRequest -> doService -> doDispatch -> preHandle..post..after ... 

->processDispatchResult ->publishRequestHandledEvent

        

猜你喜欢

转载自blog.csdn.net/qq_41750725/article/details/87617432