spring mvc 源码分析之总流程

spring mvc 源码分析

前言

废话不多说,直接上图。所有请求在spring mvc中的大致执行流程图
在这里插入图片描述
在这里插入图片描述

所有的请求都最终会被doPost和doGet所处理

一、断点开始分析源码

结合上一篇文章搭建的案例
搭建案例
开始分析
具体逻辑处理之前 打上断点在这里插入图片描述
页面跳转之前 打上断点
在这里插入图片描述

一、DispatcherServlet

DispatcherServlet的继承关系

从源码来看 DispatcherServlet 继承了FrameworkServlet ,FrameworkServlet 继承HttpServletBean ,HttpServletBean 继承HttpServlet ,HttpServlet 继承GenericServlet抽象类。

// 从源码来看 DispatcherServlet 继承了FrameworkServlet 
public class DispatcherServlet extends FrameworkServlet 


public abstract class FrameworkServlet extends HttpServletBean implements ApplicationContextAware


public abstract class HttpServletBean extends HttpServlet implements EnvironmentCapable, EnvironmentAware 


public abstract class HttpServlet extends GenericServlet

doPost和doGet在哪里实现的

通过源码查看 doGet和doPost 最终是在FrameworkServlet 进行重写。因此我们需要重点观察FrameworkServlet
从下图

调用栈分析

在这里插入图片描述

先调用了FrameworkServlet .service方法
/**
	 * Override the parent class implementation in order to intercept PATCH requests.
	 */
	@Override
	protected void service(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {

    // 解析出当前的请求方式
 /*
    因为HttpServlet中是没有定义doPatch方法的,所以规定
    if(是doPatch类型)
        就交由本类(FrameworkServlet)内的doPatch方法运行。
    else
        调用父类(HttpServlet)的service方法。
    */
		HttpMethod httpMethod = HttpMethod.resolve(request.getMethod());
		if (httpMethod == HttpMethod.PATCH || httpMethod == null) {
			processRequest(request, response);
		}
		else {
			super.service(request, response);
		}
	}
super.service(request, response)

里面主要对各种请求简单处理 并没有正在处理,真正处理都在FrameworkServlet 中

  protected void doGet(HttpServletRequest req, HttpServletResponse resp)
        throws ServletException, IOException
    {
        String protocol = req.getProtocol();
        String msg = lStrings.getString("http.method_get_not_supported");
        if (protocol.endsWith("1.1")) {
            resp.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED, msg);
        } else {
            resp.sendError(HttpServletResponse.SC_BAD_REQUEST, msg);
        }
    }
    
 protected void doPost(HttpServletRequest req, HttpServletResponse resp)
        throws ServletException, IOException
    {
        String protocol = req.getProtocol();
        String msg = lStrings.getString("http.method_post_not_supported");
        if (protocol.endsWith("1.1")) {
            resp.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED, msg);
        } else {
            resp.sendError(HttpServletResponse.SC_BAD_REQUEST, msg);
        }
    }

FrameworkServlet 中的doGet和doPost

通过源码 可以看出无论是doGet还是doPost都调用了processRequest(request, response)方法进行处理

	/**
	 * Delegate GET requests to processRequest/doService.
	 * <p>Will also be invoked by HttpServlet's default implementation of {@code doHead},
	 * with a {@code NoBodyResponse} that just captures the content length.
	 * @see #doService
	 * @see #doHead
	 */
	@Override
	protected final void doGet(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {

		processRequest(request, response);
	}

	/**
	 * Delegate POST requests to {@link #processRequest}.
	 * @see #doService
	 */
	@Override
	protected final void doPost(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {

		processRequest(request, response);
	}

FrameworkServlet 类中的processRequest(request, response) 进行一直处理
/**
	 * Process this request, publishing an event regardless of the outcome.
	 * <p>The actual event handling is performed by the abstract
	 * {@link #doService} template method.
	 */
	protected final void processRequest(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {

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

		// 获取上一个请求保存的LocaleContext
		LocaleContext previousLocaleContext = LocaleContextHolder.getLocaleContext();
		// 建立新的LocaleContext
		LocaleContext localeContext = buildLocaleContext(request);

		// 获取上一个请求保存的RequestAttributes
		RequestAttributes previousAttributes = RequestContextHolder.getRequestAttributes();
		// 建立新的RequestAttributes
		ServletRequestAttributes requestAttributes = buildRequestAttributes(request, response, previousAttributes);

		// 异步处理器
		WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
		asyncManager.registerCallableInterceptor(FrameworkServlet.class.getName(), new RequestBindingInterceptor());

		// 新的RequestAttributes设置进LocalThread
		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);
		}
	}
DispatcherServlet.doService(request, response) 重定向携带的参数处理
@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;
		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);
				}
			}
		}
	}
DispatcherServlet.doDispatch(HttpServletRequest request, HttpServletResponse response) 开始真正的处理

请求到达DispatcherServlet 通过这个方法进行处理和返回

这个方法就是最关键的方法,里面包含了整个spring Mvc的执行流程,重要程度跟spring的refresh()一样十分重要,阅读源码时找到方法入口就不会太难了

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);
				/**
				 * 拿到当前的请求controller 也就是handler 处理器
				 * 这里并不会直接返回 controller 而是返回handlerExecutionChain 请求处理链对象
				 * 该对象封装了Handler 和 Inteceptor
				 */
				// Determine handler for the current request.
				mappedHandler = getHandler(processedRequest);
				if (mappedHandler == null) {
					// 如果handler 为空,则返回404
					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.
				// 处理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.
				// 实际处理器处理请求,返回结果视图对象
				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) {
			// 最终会调用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);
				}
			}
		}
	}

步骤

第一步

通过getHandler⽅法,获取到能够处理当前请求的handlerExecutionChain,它包含handler(处理器对象)和Inteceptor(拦截器对象)。

第二步

通过getHandlerAdapter⽅法,传入处理器对象,获取到能够处理当前handler的处理器适配器对象。

第三步

mappedHandler.applyPreHandle(processedRequest, response)) 拦截器 进入handler之前拦截处理。也就是preHandle() 方法的调用,如果方法返回false将不在往后面执行。

第四步

ha.handle(processedRequest, response, mappedHandler.getHandler())处理器适配器调用handler,处理请求并封装返回ModelAndView对象

第五步

mappedHandler.applyPostHandle(processedRequest, response, mv) 拦截器 跳出handler之前拦截处理 ,也就是调用其postHandle方法,进行处理。

第六步
processDispatchResult(processedRequest,response,mappedHandler,mv,dispatchException) 进行视图的解析和渲染。

总结

本文主要对spring mvc 对于一个请求时如何处理的 给出了一个大致的流程,后续将会通过关键步骤 源码的解析,一起来感受spring mvc的强大和处理流程与方法。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

起风了 收衣服

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值