SpringMVC学习 十五 DispatcherServlet的doService方法

一、doService方法解读

在SpringMVC种,如果一个请求被DispatcherServlet拦截,就会进入这个DispatcherServlet的doService方法。

在doService方法中,会把DispatcherServlet初始化时创建的WebApplication等信息绑定到请求中,这样方便后续处理流程中其他组件使用。代码如下:

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

		// 向请求request中绑定 webApplication、localeResolver、themeResolver等组件
		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);
				}
			}
		}
	}

二、RequestContextUtils

在Spring与SpringMVC整合之后,

  • Spring的根应用上下文(也称根容器)会放在ServletContext中,以一个属性的形式存在。key值为org.springframework.web.context.WebApplicationContext.ROOT
  • SpringMVC的应用上下文(也称子容器)会被两个地方引用。一个是DispatcherServlet的父类FrameworkServlet的webApplicationContext属性引用。另外一个就是在ServletContext的属性中也可以引用到,key值的命名规则是
    FrameworkServlet.class.getName() + ".CONTEXT."+${servletName}
    if (this.publishContext) {
      // 把SpringMVC的应用上下文发布到ServletContext中
      String attrName = getServletContextAttributeName();
      getServletContext().setAttribute(attrName, wac);
    }

在SpringMVC有一个工具类RequestContextUtils,这个工具类可以获取到SpringMVC的应用上下文,刚开始是从Request中获取,如果获取不到就用WebApplicationContextUtils工具从ServletContext获取,不过此时获取的是根应用上下文。

代码如下:

	public static WebApplicationContext findWebApplicationContext(
			HttpServletRequest request, @Nullable ServletContext servletContext) {

		WebApplicationContext webApplicationContext = (WebApplicationContext) request.getAttribute(
				DispatcherServlet.WEB_APPLICATION_CONTEXT_ATTRIBUTE);
		if (webApplicationContext == null) {
			if (servletContext != null) {
				webApplicationContext = WebApplicationContextUtils.getWebApplicationContext(servletContext);
			}
			if (webApplicationContext == null) {
				webApplicationContext = ContextLoader.getCurrentWebApplicationContext();
			}
		}
		return webApplicationContext;
	}
原文地址:https://www.cnblogs.com/cplinux/p/15364772.html