一文带你搞懂DispatcherServlet前端控制器



DispatcherServlet前端控制器

配置

DispatcherServlet充当SpringMVC的前端控制器,整个流程控制的中心,控制其它组件执行,统一调度,降低组件之间的耦合性,提高每个组件的扩展性。与其他Servlet一样,DispatcherServlet必须在Web应用程序的web.xml文件中进行配置

web.xml配置

<!-- springmvc会过滤掉.html的 导致视图解析器无法找到
     如果只是使用jsp资源而未使用html的话可以不配置该项
-->
<servlet-mapping>
  <servlet-name>default</servlet-name>
  <url-pattern>*.html</url-pattern>
</servlet-mapping>
<!-- 配置DispatcherServlet -->
<servlet>
  <servlet-name>DispatcherServlet</servlet-name>
  <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
  <!-- 初始化参数:配置Springmvc配置文件的位置和名称
        默认配置文件为:/WEB-INF/<servlet-name>-servlet.xml
  -->
  <init-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>classpath:springmvc.xml</param-value>
  </init-param>
  <!-- 指定servlet加载顺序,指定的话,tomcat在容器启动的时候就会初始化并加载servlet实例,值越小,越早加载;如果不指定该值,表示调用servlet请求时在初始化并加载servlet实例 -->
  <!-- 在程序启动的时候根据contextConfigLocation配置的xml文件开始配置spring应用上下文,初始化组件 -->
  <load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
  <servlet-name>DispatcherServlet</servlet-name>
  <!-- url-pattern匹配:
	精确匹配:/a
 目录匹配:/*
扩展名匹配:*.do
默认匹配:/
这里要配置为/,使之所有在web.xml中找不到匹配元素的url,都会交给DispatcherServlet来处理
-->
  <url-pattern>/</url-pattern>
</servlet-mapping>
<!-- 处理静态资源 -->
<mvc:resources mapping="/images/**" location="/images/" cache-period="31556926"></mvc:resources>
<mvc:resources mapping="/js/**" location="/js/" cache-period="31556926"></mvc:resources>
<mvc:resources mapping="/css/**" location="/css/" cache-period="31556926"></mvc:resources>
serlvet3.0扩展

在servlet3.0中,可以不使用xml配置servlet,容器会在类路径中查找实现ServletContainerInitializer接口的类,会使用它来配置Servlet容器,在spring中提供了该接口的实现SpringServletContainerInitializer,该实现类会去查找实现WebApplicationInitializer接口的类来完成配置任务,AbstractAnnotationConfigDispatcherServletInitializer就是该接口的基础实现,可以通过继承AbstractAnnotationConfigDispatcherServletInitializer类来进行配置DispatcherServlet

WebApplicationInitializer的作用就类似于web.xml,项目启动时会自动执行onStartup方法

需要实现三个方法

// 将一个或多个路径映射到DispacherServlet
protected abstract String[] getServletMappings();

// 返回带有@Configuration注解的类用来定义ContextLoaderLister创建应用上下文中的bean
	protected abstract Class<?>[] getRootConfigClasses();

	// 返回带有@Configuration注解的类用来定义DispacherServlet应用上下文中的bean
	protected abstract Class<?>[] getServletConfigClasses();
静态资源请求问题

因为DispatcherServlet的<url-pattern>配置的是/,针对的是所有请求,对于一些的静态资源(如.js、.css)等也会经过DispatcherServlet,但是DispatcherServlet是处理动态请求的,无法处理静态资源

可以配置<mvc:default-servlet-handler/>来解决,作用是处理静态资源,会在SpringMVC上下文中定义一个DefaultServletHttpRequestHandle,对进行DispatcherServlet的请求进行筛选,如果发现是没有经过映射的请求,就将请求交给WEB服务器默认的Servlet来处理,否则交由DispatcherServlet来处理

default-servlet-name默认是default,如果不是default需要显式的进行配置(看所使用的web服务器,tomcat是default)

<mvc:default-servlet-handler default-servlet-name="default"/>

需要注意的是,配置了<mvc:default-servlet-handler/>之后,@RequestMapping的映射会失效,需要加上<mvc:annotation-driven/>配置

源码分析

先看一下DispatcherServlet结构,其本质就是一个Servlet

DispatcherServlet结构

DispatcherServlet的工作大致可以分为两个部分:一是初始化部分,本质就是一个Servlet,在init方法时会进行初始化,最终调用initStrategies方法;二是对于HTTP请求进行响应,调用doGet和doPost方法,最终调用doDispatch方法

DispatcherServlet处理过程

初始化
// DispatcherServlet继承了FrameworkServlet类,FrameworkServlet继承了HttpServletBean类,HttpServletBean继承了HttpServlet,所以DispatcherServlet本质上是一个Servlet
public class DispatcherServlet extends FrameworkServlet

public abstract class FrameworkServlet extends HttpServletBean implements ApplicationContextAware
  
public abstract class HttpServletBean extends HttpServlet implements EnvironmentCapable, EnvironmentAware

HttpServletBean的init方法

public final void init() throws ServletException {

   // Set bean properties from init parameters.
  // 获取初始化参数 init-param
   PropertyValues pvs = new ServletConfigPropertyValues(getServletConfig(), this.requiredProperties);
   if (!pvs.isEmpty()) {
      try {
        // 将当前的servlet类转换为一个BeanWrapper,使得可以用spring的方式来对init-param参数进行注入
         BeanWrapper bw = PropertyAccessorFactory.forBeanPropertyAccess(this);
         ResourceLoader resourceLoader = new ServletContextResourceLoader(getServletContext());
        // 注册自定义属性编辑器
         bw.registerCustomEditor(Resource.class, new ResourceEditor(resourceLoader, getEnvironment()));
        // 空实现
         initBeanWrapper(bw);
        // 属性注入
         bw.setPropertyValues(pvs, true);
      }
      catch (BeansException ex) {
         
         throw ex;
      }
   }

   // Let subclasses do whatever initialization they like.
  // 调用子类的initServletBean,来进行servletBean的初始化
  // org.springframework.web.servlet.FrameworkServlet#initServletBean
   initServletBean();
}

FrameworkServlet的initServletBean方法

protected final void initServletBean() throws ServletException {   
     // 初始化上下文
      this.webApplicationContext = initWebApplicationContext();
     // 空实现
      initFrameworkServlet();
}

// 创建或刷新WebApplicationContext实例并对servlet功能所使用的变量进行初始化
protected WebApplicationContext initWebApplicationContext() {
  // 这是父容器,获取根上下文,ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE,是在ContextLoaderListener初始化过程中建立的
		WebApplicationContext rootContext =
				WebApplicationContextUtils.getWebApplicationContext(getServletContext());
  // 这是子容器
		WebApplicationContext wac = null;

		if (this.webApplicationContext != null) {
			// A context instance was injected at construction time -> use it
      // 通过构造器创建的实例
			wac = this.webApplicationContext;
			if (wac instanceof ConfigurableWebApplicationContext) {
				ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext) wac;
				if (!cwac.isActive()) {
					// The context has not yet been refreshed -> provide services such as
					// setting the parent context, setting the application context id, etc
					if (cwac.getParent() == null) {
						// The context instance was injected without an explicit parent -> set
						// the root application context (if any; may be null) as the parent
            // 根上下文作为该上下文的双亲上下文
						cwac.setParent(rootContext);
					}
          // 刷新上下文环境
					configureAndRefreshWebApplicationContext(cwac);
				}
			}
		}
		if (wac == null) {
			// No context instance was injected at construction time -> see if one
			// has been registered in the servlet context. If one exists, it is assumed
			// that the parent context (if any) has already been set and that the
			// user has performed any initialization such as setting the context id
      // 根据contextAttribute属性从ServletContext中加载WebApplicationContext
			wac = findWebApplicationContext();
		}
  // 通过上述两种方式都没有找到,则说明不存在WebApplicationContext实例,则进行创建
		if (wac == null) {
			// No context instance is defined for this servlet -> create a local one
			wac = createWebApplicationContext(rootContext);
		}

		if (!this.refreshEventReceived) {
			// Either the context is not a ConfigurableApplicationContext with refresh
			// support or the context injected at construction time had already been
			// refreshed -> trigger initial onRefresh manually here.
      // 调用DispatcherServlet#initStrategies方法,初始化DispatcherServlet的默认策略配置
			onRefresh(wac);
		}
		// 把当前创建的上下文存到ServletContext中
		if (this.publishContext) {
			// Publish the context as a servlet context attribute.
			String attrName = getServletContextAttributeName();
			getServletContext().setAttribute(attrName, wac);
			
		}

		return wac;
	}

protected WebApplicationContext createWebApplicationContext(ApplicationContext parent) {
		Class<?> contextClass = getContextClass();
		
		if (!ConfigurableWebApplicationContext.class.isAssignableFrom(contextClass)) {
			throw new ApplicationContextException(
					"Fatal initialization error in servlet with name '" + getServletName() +
					"': custom WebApplicationContext class [" + contextClass.getName() +
					"] is not of type ConfigurableWebApplicationContext");
		}
  // contextClass使用的是默认的DEFAULT_CONTEXT_CLASS,XmlWebApplicationContext.class
  // 通过反射实例化contextClass
		ConfigurableWebApplicationContext wac =
				(ConfigurableWebApplicationContext) BeanUtils.instantiateClass(contextClass);

		wac.setEnvironment(getEnvironment());
  // 配置双亲上下文为传入的根上下文,parent是在ConetextLoderListener中创建的实例
		wac.setParent(parent);
		wac.setConfigLocation(getContextConfigLocation());
// 初始化spring环境
		configureAndRefreshWebApplicationContext(wac);

		return wac;
	}
配置刷新WebApplicationContext
protected void configureAndRefreshWebApplicationContext(ConfigurableWebApplicationContext wac) {
   if (ObjectUtils.identityToString(wac).equals(wac.getId())) {
      // The application context id is still set to its original default value
      // -> assign a more useful id based on available information
      if (this.contextId != null) {
         wac.setId(this.contextId);
      }
      else {
         // Generate default id...
         wac.setId(ConfigurableWebApplicationContext.APPLICATION_CONTEXT_ID_PREFIX +
               ObjectUtils.getDisplayString(getServletContext().getContextPath()) + '/' + getServletName());
      }
   }

   wac.setServletContext(getServletContext());
   wac.setServletConfig(getServletConfig());
   wac.setNamespace(getNamespace());
  // 监听器  该监听器在接收到ContextRefreshedEvent事件后,会调用onRefresh方法完成刷新
   wac.addApplicationListener(new SourceFilteringListener(wac, new ContextRefreshListener()));

   // The wac environment's #initPropertySources will be called in any case when the context
   // is refreshed; do it eagerly here to ensure servlet property sources are in place for
   // use in any post-processing or initialization that occurs below prior to #refresh
   ConfigurableEnvironment env = wac.getEnvironment();
   if (env instanceof ConfigurableWebEnvironment) {
      ((ConfigurableWebEnvironment) env).initPropertySources(getServletContext(), getServletConfig());
   }

   postProcessWebApplicationContext(wac);
   applyInitializers(wac);
  // 加载配置文件,这里就是执行org.springframework.context.support.AbstractApplicationContext#refresh方法,与spring中加载上下文是一样的
   wac.refresh();
}
onRefresh

用于刷新spring在web功能实现中所必须使用的全局变量

protected void onRefresh(ApplicationContext context) {
		initStrategies(context);
	}

// 下边的组件如果没有配置默认会读取org.springframework.web.servlet下的DispatcherServlet.properties
protected void initStrategies(ApplicationContext context) {
  // 初始化MultipartResolver,获取beanName为multipartResolver的bean,没有默认值,必须手动配置,用于处理上传请求,处理方法是将普通的request包装成MultipartHttpServletRequest,可以直接调用getFile方法获取File
   initMultipartResolver(context);
  // 初始化LocaleResolver,获取beanName为localeResolver的bean,如果没有默认DispatcherServlet.properties获取
  //国际化解析器,使用的地方有两个,一是ViewResolver视图解析的时候;二是用到国际化资源或者主题的时候。
   initLocaleResolver(context);
  // 初始化ThemeResolver,获取beanName为themeResolver的bean,如果没有默认DispatcherServlet.properties获取
  //用于解析主题。SpringMVC中一个主题对应 一个properties文件,里面存放着跟当前主题相关的所有资源,如图片、css样式等。SpringMVC的主题也支持国际化
   initThemeResolver(context);
  // 初始化HandlerMappings,如果配置detectAllHandlerMappings为false的话,只会获取beanName为handlerMapping的bean,否则会找所有类型为HandlerMapping的bean,默认是true,如果没有默认DispatcherServlet.properties获取
  //初始化处理器映射器
   initHandlerMappings(context);
  // 初始化HandlerAdapters,如果配置detectAllHandlerAdapters为false的话,只会获取beanName为handlerAdapter的bean,否则会找所有类型为HandlerAdapter的bean,默认是true,如果没有默认DispatcherServlet.properties获取
  //初始化处理器适配器
   initHandlerAdapters(context);
  // 初始化HandlerExceptionResolvers,如果配置detectAllHandlerExceptionResolvers为false的话,只会获取beanName为handlerExceptionResolver的bean,否则会找所有类型为HandlerExceptionResolver的bean,默认是true,如果没有默认DispatcherServlet.properties获取
  // 初始化异常处理器,对异常情况进行处理,在SpringMVC中就是HandlerExceptionResolver。
   initHandlerExceptionResolvers(context);
  // 初始化RequestToViewNameTranslator,获取beanName为viewNameTranslator的bean,如果没有默认DispatcherServlet.properties获取
  //有的Handler处理完后并没有设置View也没有设置ViewName,这时就需要RequestToViewNameTranslator从request获取ViewName了
   initRequestToViewNameTranslator(context);
  // 初始化ViewResolvers,如果配置detectAllViewResolvers为false的话,只会获取beanName为viewResolver的bean,否则会找所有类型为ViewResolver的bean,默认是true,如果没有默认DispatcherServlet.properties获取
  //ViewResolver用来将String类型的视图名和Locale解析为View类型的视图。View是用来渲染页面的,也就是将程序返回的参数填入模板里,生成html(也可能是其它类型)文件。
   initViewResolvers(context);
  // 初始化FlashMapManager,获取beanName为flashMapManager的bean,如果没有默认DispatcherServlet.properties获取
  //用来管理FlashMap的,FlashMap主要用在redirect重定向中传递参数。
   initFlashMapManager(context);
}

上述默认值是从DispatcherServlet.properties中取的

# 国际化解析器
org.springframework.web.servlet.LocaleResolver=org.springframework.web.servlet.i18n.AcceptHeaderLocaleResolver
# 主题解析器
org.springframework.web.servlet.ThemeResolver=org.springframework.web.servlet.theme.FixedThemeResolver
# HandlerMapping
org.springframework.web.servlet.HandlerMapping=org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping,\
	org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping
# 处理器适配器
org.springframework.web.servlet.HandlerAdapter=org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter,\
	org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter,\
	org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter
# 异常解析器
org.springframework.web.servlet.HandlerExceptionResolver=org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerExceptionResolver,\
	org.springframework.web.servlet.mvc.annotation.ResponseStatusExceptionResolver,\
	org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver
# 策略视图名称转换器
org.springframework.web.servlet.RequestToViewNameTranslator=org.springframework.web.servlet.view.DefaultRequestToViewNameTranslator
# 视图解析器
org.springframework.web.servlet.ViewResolver=org.springframework.web.servlet.view.InternalResourceViewResolver
# FlashMap管理器
org.springframework.web.servlet.FlashMapManager=org.springframework.web.servlet.support.SessionFlashMapManager
介绍各个组件

LocaleResolver

国际化处理

  • AcceptHeaderLocaleResolver 基于URL参数的配置,可以读取url中locale=zh_CN来控制国际化参数
  • CookieLocaleResolver 基于cookie的配置,可以通过浏览器的cookie设置获取Locale对象
  • SessionLocaleResolver 基于session的配置,可以公国检验session的预置的属性来解析,如果没有则会根据请求头中的accept-language来确定

ThemeResolver

主题处理,根据主题控制网页风格

  • FixedThemeResolver 选择一个固定的主题
  • CookieThemeResolver 用于实现用户所选的主题,以cookie的形式存放在客户端的机器上
  • SessionThemeResolver 用于主题存放在session中

HandlerAdapter

  • HttpRequestHandlerAdapter 仅支持HTTP请求处理器的适配,将HTTP请求对象和响应对象传递给HTTP请求处理器的实现,不需要返回值,主要应用在基于HTTP的远程调用实现上
  • SimpleControllerHandlerAdapter 将HTTP请求适配到一个控制器的实现进行处理
  • AnnotationMethodHandlerAdapter 在3.2被废弃,使用RequestMappingHandlerAdapter,基于注解的实现

HandlerExceptionResolver

进行异常处理

处理请求

请求过来之后进行统一处理,由service()/doGet()/doPost()等方法调用

// doPost -> processRequest -> doService -> doDispatch
protected final void doPost(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {

		processRequest(request, response);
	}

protected final void processRequest(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {

		long startTime = System.currentTimeMillis();
		Throwable failureCause = null;
	// 提取当前线程的LocaleContext和RequestAttributes,在请求结束后进行重置
		LocaleContext previousLocaleContext = LocaleContextHolder.getLocaleContext();
		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和RequestAttributes绑定到当前线程,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();
			}
			// 发布消息
			publishRequestHandledEvent(request, response, startTime, failureCause);
		}
	}


protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {

		// 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;
  // include请求,对request中的Attribute进行备份
		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.
        // 还原request中的Attribute快照
				if (attributesSnapshot != null) {
					restoreAttributesAfterInclude(request, attributesSnapshot);
				}
			}
		}
	}

// 真正的请求处理
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 {
        // 检查是不是multipart类型的,如果是会将请求类型转为MultipartHttpServletRequest
         processedRequest = checkMultipart(request);
         multipartRequestParsed = (processedRequest != request);

         // Determine handler for the current request.
        // 获取处理当前请求的处理器,根据请求的URL信息去查找匹配的URL的Handler,如果查找成,并返回一个执行链HandlerExecutionChain
         mappedHandler = getHandler(processedRequest);
         if (mappedHandler == null || mappedHandler.getHandler() == null) {
           // 没有找到对应的handler,返回404
            noHandlerFound(processedRequest, response);
            return;
         }

         // Determine handler adapter for the current request.
        // 根据当前的handler获取对应的HandlerAdapter
         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;
            }
         }
					// 执行拦截器的preHandler方法,按顺序执行,如果执行过程中有拦截器的preHandler方法返回false,则需要执行拦截器的afterCompletion方法,按照反向顺序进行执行 for (int i = this.interceptorIndex; i >= 0; i--)
         if (!mappedHandler.applyPreHandle(processedRequest, response)) {
            return;
         }

         // Actually invoke the handler.
        // 调用handler处理器逻辑,即业务代码Controller
         mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
				// 异步处理直接返回
         if (asyncManager.isConcurrentHandlingStarted()) {
            return;
         }
				// 如果没有返回view的视图名称,则采用默认的视图名称,添加前缀、后缀
         applyDefaultViewName(processedRequest, mv);
        // 执行拦截器的postHandle方法,按照反向顺序进行执行 for (int i = interceptors.length - 1; i >= 0; i--)
         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);
      }
     // 处理返回结果,包括视图渲染,处理异常,以及拦截器的afterCompletion方法
      processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
   }
   catch (Exception ex) {
     // 异常处理,以及拦截器的afterCompletion方法
      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.
        // 清除multipart上传的资源
         if (multipartRequestParsed) {
            cleanupMultipart(processedRequest);
         }
      }
   }
}

doDispatch处理

getHandler
protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
   for (HandlerMapping hm : this.handlerMappings) {
      
      HandlerExecutionChain handler = hm.getHandler(request);
      if (handler != null) {
         return handler;
      }
   }
   return null;
}

这里就以RequestMappingHandlerMapping为例

public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
  // 获取request对应的handler
   Object handler = getHandlerInternal(request);
   if (handler == null) {
     // 如果没有,则使用默认的handler
      handler = getDefaultHandler();
   }
   if (handler == null) {
      return null;
   }
   // Bean name or resolved handler?
   if (handler instanceof String) {
      String handlerName = (String) handler;
      handler = getApplicationContext().getBean(handlerName);
   }

   HandlerExecutionChain executionChain = getHandlerExecutionChain(handler, request);
   if (CorsUtils.isCorsRequest(request)) {
      CorsConfiguration globalConfig = this.globalCorsConfigSource.getCorsConfiguration(request);
      CorsConfiguration handlerConfig = getCorsConfiguration(handler, request);
      CorsConfiguration config = (globalConfig != null ? globalConfig.combine(handlerConfig) : handlerConfig);
      executionChain = getCorsHandlerExecutionChain(request, executionChain, config);
   }
   return executionChain;
}
ha.handle

通过适配器去调用Handler的实际逻辑,以RequestMappingHandlerAdapter为例

protected ModelAndView handleInternal(HttpServletRequest request,
      HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {

   ModelAndView mav;
   checkRequest(request);

   // Execute invokeHandlerMethod in synchronized block if required.
  // 如果需要session内的同步执行
   if (this.synchronizeOnSession) {
      HttpSession session = request.getSession(false);
      if (session != null) {
         Object mutex = WebUtils.getSessionMutex(session);
         synchronized (mutex) {
            mav = invokeHandlerMethod(request, response, handlerMethod);
         }
      }
      else {
         // No HttpSession available -> no mutex necessary
         mav = invokeHandlerMethod(request, response, handlerMethod);
      }
   }
   else {
      // No synchronization on session demanded at all...
     // 调用用户逻辑
      mav = invokeHandlerMethod(request, response, handlerMethod);
   }

   if (!response.containsHeader(HEADER_CACHE_CONTROL)) {
      if (getSessionAttributesHandler(handlerMethod).hasSessionAttributes()) {
         applyCacheSeconds(response, this.cacheSecondsForSessionAttributeHandlers);
      }
      else {
         prepareResponse(response);
      }
   }

   return mav;
}
invokeHandlerMethod
protected ModelAndView invokeHandlerMethod(HttpServletRequest request,
      HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {

   ServletWebRequest webRequest = new ServletWebRequest(request, response);
   try {
     // 获取数据绑定 initBinder
      WebDataBinderFactory binderFactory = getDataBinderFactory(handlerMethod);
     // 获取@SessionAttributes
      ModelFactory modelFactory = getModelFactory(handlerMethod, binderFactory);

      ServletInvocableHandlerMethod invocableMethod = createInvocableHandlerMethod(handlerMethod);
      invocableMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers);
      invocableMethod.setHandlerMethodReturnValueHandlers(this.returnValueHandlers);
      invocableMethod.setDataBinderFactory(binderFactory);
      invocableMethod.setParameterNameDiscoverer(this.parameterNameDiscoverer);

      ModelAndViewContainer mavContainer = new ModelAndViewContainer();
      mavContainer.addAllAttributes(RequestContextUtils.getInputFlashMap(request));
      modelFactory.initModel(webRequest, mavContainer, invocableMethod);
      mavContainer.setIgnoreDefaultModelOnRedirect(this.ignoreDefaultModelOnRedirect);

      AsyncWebRequest asyncWebRequest = WebAsyncUtils.createAsyncWebRequest(request, response);
      asyncWebRequest.setTimeout(this.asyncRequestTimeout);

      WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
      asyncManager.setTaskExecutor(this.taskExecutor);
      asyncManager.setAsyncWebRequest(asyncWebRequest);
      asyncManager.registerCallableInterceptors(this.callableInterceptors);
      asyncManager.registerDeferredResultInterceptors(this.deferredResultInterceptors);

      if (asyncManager.hasConcurrentResult()) {
         Object result = asyncManager.getConcurrentResult();
         mavContainer = (ModelAndViewContainer) asyncManager.getConcurrentResultContext()[0];
         asyncManager.clearConcurrentResult();
         
         invocableMethod = invocableMethod.wrapConcurrentResult(result);
      }
			// 进行方法调用
      invocableMethod.invokeAndHandle(webRequest, mavContainer);
      if (asyncManager.isConcurrentHandlingStarted()) {
         return null;
      }

      return getModelAndView(mavContainer, modelFactory, webRequest);
   }
   finally {
      webRequest.requestCompleted();
   }
}
processDispatchResult处理请求结果
private void processDispatchResult(HttpServletRequest request, HttpServletResponse response,
      HandlerExecutionChain mappedHandler, ModelAndView mv, Exception exception) throws Exception {

   boolean errorView = false;

  // 请求处理过程中有异常抛出
   if (exception != null) {
      if (exception instanceof ModelAndViewDefiningException) {
         mv = ((ModelAndViewDefiningException) exception).getModelAndView();
      }
      else {
         Object handler = (mappedHandler != null ? mappedHandler.getHandler() : null);
        // 调用异常处理器处理异常
         mv = processHandlerException(request, response, handler, exception);
         errorView = (mv != null);
      }
   }

   // Did the handler return a view to render?
  // 渲染页面
   if (mv != null && !mv.wasCleared()) {
      render(mv, request, response);
      if (errorView) {
         WebUtils.clearErrorRequestAttributes(request);
      }
   }
   else {
      
   }

   if (WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) {
      // Concurrent handling started during a forward
      return;
   }
		// 触发Interceptor.afterCompletion
   if (mappedHandler != null) {
      mappedHandler.triggerAfterCompletion(request, response, null);
   }
}
异常解析processHandlerException
protected ModelAndView processHandlerException(HttpServletRequest request, HttpServletResponse response,
      Object handler, Exception ex) throws Exception {

   // Check registered HandlerExceptionResolvers...
   ModelAndView exMv = null;
  // 使用异常处理器来进行处理
   for (HandlerExceptionResolver handlerExceptionResolver : this.handlerExceptionResolvers) {
      exMv = handlerExceptionResolver.resolveException(request, response, handler, ex);
      if (exMv != null) {
         break;
      }
   }
   if (exMv != null) {
      if (exMv.isEmpty()) {
         request.setAttribute(EXCEPTION_ATTRIBUTE, ex);
         return null;
      }
      // We might still need view name translation for a plain error model...
      if (!exMv.hasView()) {
         exMv.setViewName(getDefaultViewName(request));
      }
      if (logger.isDebugEnabled()) {
         logger.debug("Handler execution resulted in exception - forwarding to resolved error view: " + exMv, ex);
      }
      WebUtils.exposeErrorRequestAttributes(request, ex, getServletName());
      return exMv;
   }

   throw ex;
}

参考文献

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

拾光师

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

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

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

打赏作者

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

抵扣说明:

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

余额充值