栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

关于SpringMvc的DispatcherServlet的工作流程的理解与梳理

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

关于SpringMvc的DispatcherServlet的工作流程的理解与梳理

          首先,我们看一下DispatcherServlet的继承关系图。这里,我们着重看一下Servlet部分的继承树。下图中我们可以看到,DispatcherServlet就是实现了Servlet接口。而用来处理请求的service方法在其父类frameworkServlet中进行了重写。

     其次,咱们看一下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 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);
				}
			}
			if (this.parseRequestPath) {
				ServletRequestPathUtils.setParsedRequestPath(previousRequestPath, request);
			}
		}
	}

 那么,咱们就着重看一下doDispatcherService是如何处理请求的,其源码如下:

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

				// 把要调的接口和拦截器封装到mappedHandler里。
				mappedHandler = getHandler(processedRequest);
				if (mappedHandler == null) {
					noHandlerFound(processedRequest, response);
					return;
				}

				// 定义Handler适配器,负责执行Handler里面的接口或拦截器的逻辑
				HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());

				
				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;
					}
				}
                 //调用拦截器中的PreHandle方法,如果方法的返回结果为false,直接return,结束后续操作。
				if (!mappedHandler.applyPreHandle(processedRequest, response)) {
					return;
				}

				// 调用适配器中的handle方法,进入servlet接口方法中,对实际请求进行处理,并将返回结果赋值到视图对象中
				mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

				if (asyncManager.isConcurrentHandlingStarted()) {
					return;
				}

				applyDefaultViewName(processedRequest, mv);
                //调用拦截器中的PostHandle方法
				mappedHandler.applyPostHandle(processedRequest, response, mv);
			}
			catch (Exception ex) {
				dispatchException = ex;
			}
			catch (Throwable err) {
				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:它对处理请求的整个过程进行了监控,一旦出现异常和错误,就会激活拦截器中的afterCompletion方法,关闭所有的打开的资源,进行资源释放。(由最外层的catch代码块定义)

2:如果是文件上传的请求,在finally代码块中,进行了资源清空操作,释放所有相关资源

3:当Dispatcher接收到一个请求后,它会把请求中的URL地址的相关接口方法及拦截器封装进mappedHandler对象中。通过断点(如下图),我们可以清楚的看到mappedHandler对象中包含handler对象(即咱们请求的servlet接口方法)和interceptorList(拦截器)。其中handler对象中定义的bean和method方法,用来进行映射调用

 

4:Dispatcher根据mappedHandler对象中的接口方法,找到一个用来处理对应方法的适配器(HandlerAdapter)并进行封装,用来进行相应的逻辑处理。(如何映射,如何赋值 等)

 5:调用拦截器中的PreHandle方法,如果方法的返回结果为false,直接return,结束后续操作。如果 返回结果为true,继续往下执行

   6:调用HandlerAdapter适配器中的handle方法,进入servlet接口方法中,对实际请求进行处理,并将返回结果赋值到视图对象中

7:调用拦截器中的PostHandle方法

8:回调processDispatchResult方法,把执行结果响应给浏览器

 以上就是我对DispatcherServlet大致的工作流程的理解和梳理,以供参考!

 

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/781752.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号