【源码系列之springMVC】(二、请求处理:processRequest)

客户端发送get或者post等请求,会调用Servelt项相对应的方法,比如get请求,就会执行Servlet的doGet方法。
进过查看,DispatcherServelt类中并没有覆盖这几种方法,根据java多态的特性,如果子类没有此方法,那么就去直接父类找。然后在FrameworkServlet类中找到了处理这些请求的方法:
在这里插入图片描述

然后我们看处理这几种请求的方法体:

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

		processRequest(request, response);
	}
	
	/**
	 * 处理Get请求
	 */
	@Override
	protected final void doGet(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {

		processRequest(request, response);
	}

	/**
	 * 处理Post请求
	 */
	@Override
	protected final void doPost(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {

		processRequest(request, response);
	}

	/**
	 * 处理Put请求
	 */
	@Override
	protected final void doPut(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {

		processRequest(request, response);
	}

	/**
	 * 处理Delete请求
	 */
	@Override
	protected final void doDelete(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {

		processRequest(request, response);
	}

所有的请求,方法里面都没有进行处理,而是统一委托给processRequest方法进行处理。FrameworkServletprocessRequest方法处理了所有请求,那么我们来看一下他的如何工作的:
此方法的注释上面说的是,这个方法处理请求,不管请求成功与否,都会发布事件,实际事件处理由Service方法执行。

	protected final void processRequest(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		// 获取系统当前时间戳
		long startTime = System.currentTimeMillis();
		// 申明一个异常顶层对象Throwable
		Throwable failureCause = null;
		// 本地化、国际化处理。
		// 获取上一个LocaleContext,这里叫上一个,是因为此方法是从ThreadLocal中获取的,获取当前线程的LocaleContext。
		LocaleContext previousLocaleContext = LocaleContextHolder.getLocaleContext();
		// 构建一个本地国际化上下文,SimpleLocaleContext
		LocaleContext localeContext = buildLocaleContext(request);
		// 获取当前绑定到线程的RequestAttributes
		RequestAttributes previousAttributes = RequestContextHolder.getRequestAttributes();
		// 构建ServletRequestAttributes
		ServletRequestAttributes requestAttributes = buildRequestAttributes(request, response, previousAttributes);

		WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
		asyncManager.registerCallableInterceptor(FrameworkServlet.class.getName(), new RequestBindingInterceptor());
		// 将localeContext和requestAttributes放入当前线程中
		initContextHolders(request, localeContext, requestAttributes);

		try {
			// 然后进入doService方法。这个方法才是大菜,上面那些都是一些准备工作,后面finally里面的都是一些收尾工作
			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);
		}
	}

我们来看看这个doService方法,这个方法FreameworkServlet没有实现,是DispatcherServlet进行实现的。
从这里可以看出,FrameworkServelt主要做的是一些准备工作,比如系统初始化的时候,也基本上是FrameworkServelt在做,这里准备一些工作也是他在做,分工还是很明确的。
我们来看 DispatcherServletdoService方法:
方法上面的注释大概意思是:将请求交给doDispatch来处理。。。怪我道行不高,搞不懂其原因。

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

		// 保留请求属性的快照,以防出现include,
		// 能够在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));
				}
			}
		}

		// 使框架对象对处理程序和视图对象可用。
		// 将web应用上下文对象放置在request域中
		request.setAttribute(WEB_APPLICATION_CONTEXT_ATTRIBUTE, getWebApplicationContext());
		// 下面都是针对于视图的一些属性,放置在request域中
		request.setAttribute(LOCALE_RESOLVER_ATTRIBUTE, this.localeResolver);
		request.setAttribute(THEME_RESOLVER_ATTRIBUTE, this.themeResolver);
		request.setAttribute(THEME_SOURCE_ATTRIBUTE, getThemeSource());
		// 看flashMap是否为null,不为空的话做如下操作。FlashMap是用于转发保存数据用的。
		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);
				}
			}
		}
	}

接着我们继续看doDispatch方法:此方法是实际处理请求的方法。

	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 {
				// 检查当前请求是不是一个MultipartHttpServletRequest请求,(文件上传请求)
				processedRequest = checkMultipart(request);
				// 将是不是文件请求赋值给multipartRequestParsed 
				multipartRequestParsed = (processedRequest != request);

				// 确定当前请求程序,也就是根据请求类型,返回不同的handler。
				mappedHandler = getHandler(processedRequest);
				if (mappedHandler == null) {
					// 如果当前请求没有handler进行处理,那么就抛出异常
					noHandlerFound(processedRequest, response);
					return;
				}

				// 获取当前处理器的适配器,这里使用到了适配器模式,
				HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());

				// 如果最后一个处理程序支持头修改,则返回最后一个处理程序。
				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;
				}

				// 实际调用处理程序。讲request,response传递过去,
				mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

				if (asyncManager.isConcurrentHandlingStarted()) {
					return;
				}
				// 如果说视图不为null,并且没有视图名称,并且有默认的视图名称,那么将视图的名称设置为默认的视图名称
				applyDefaultViewName(processedRequest, mv);
				// 执行所有的handler,就是执行我们所有的HandlerInterceptor实现类的方法。包括我们自定义的。
				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);
				}
			}
		}
	}
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值