DispatcherServlet源码解析(未完,待续)

SpringBoot版本:2.3.1.RELEASE

1 DispatcherServletAutoConfiguration

DispatcherServletSpringBoot中的自动装配是由DispatcherServletAutoConfiguration完成的。

源码:

// 指定自动配置类的优先级顺序,DispatcherServletAutoConfiguration在自动配置类中拥有最高优先级
@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE)
// 指定该类为配置类
@Configuration(proxyBeanMethods = false)
// 只有在当前应用是一个Servlet Web应用的时候,这个配置类才生效
@ConditionalOnWebApplication(type = Type.SERVLET)
// 只有在classpath下存在DispatcherServlet类的时候,这个配置类才生效
@ConditionalOnClass(DispatcherServlet.class)
// 在ServletWebServerFactoryAutoConfiguration配置之后,才会配置这个类
@AutoConfigureAfter(ServletWebServerFactoryAutoConfiguration.class)
public class DispatcherServletAutoConfiguration {

	/*
	 * 匹配"/"路径的DispatcherServlet的默认bean名字
	 */
	public static final String DEFAULT_DISPATCHER_SERVLET_BEAN_NAME = "dispatcherServlet";

	/*
	 * ServletRegistrationBean的默认bean名字
	 */
	public static final String DEFAULT_DISPATCHER_SERVLET_REGISTRATION_BEAN_NAME = "dispatcherServletRegistration";

    /**
     * =============================================================
     * 嵌套配置类DispatcherServletConfiguration
     * 1、定义并实例化DispatcherServlet的bean
     * 2、实例化MultipartResolver的bean
     * =============================================================
     */
    // 指定该类为配置类
	@Configuration(proxyBeanMethods = false)
    // 只有在DefaultDispatcherServletCondition条件类被满足的情况下,这个配置类才生效
	@Conditional(DefaultDispatcherServletCondition.class)
    // 只有在classpath下存在ServletRegistration类的时候,这个配置类才生效
	@ConditionalOnClass(ServletRegistration.class)
    // 实例化WebMvcProperties配置属性类
	@EnableConfigurationProperties(WebMvcProperties.class)
	protected static class DispatcherServletConfiguration {

        // 实例化DispatcherServlet bean,并命名为dispatcherServlet
		@Bean(name = DEFAULT_DISPATCHER_SERVLET_BEAN_NAME)
		public DispatcherServlet dispatcherServlet(WebMvcProperties webMvcProperties) {
			DispatcherServlet dispatcherServlet = new DispatcherServlet();
			dispatcherServlet.setDispatchOptionsRequest(webMvcProperties.isDispatchOptionsRequest());
			dispatcherServlet.setDispatchTraceRequest(webMvcProperties.isDispatchTraceRequest());
			dispatcherServlet.setThrowExceptionIfNoHandlerFound(webMvcProperties.isThrowExceptionIfNoHandlerFound());
			dispatcherServlet.setPublishEvents(webMvcProperties.isPublishRequestHandledEvents());
			dispatcherServlet.setEnableLoggingRequestDetails(webMvcProperties.isLogRequestDetails());
			return dispatcherServlet;
		}

        // 实例化MultipartResolver bean,名字为multipartResolver
		@Bean
        // 只有在classpath下存在MultipartResolver类石才生效
		@ConditionalOnBean(MultipartResolver.class)
        // 只有在DispatcherServlet.MULTIPART_RESOLVER_BEAN_NAME实例bean不存在的时候才生效
		@ConditionalOnMissingBean(name = DispatcherServlet.MULTIPART_RESOLVER_BEAN_NAME)
		public MultipartResolver multipartResolver(MultipartResolver resolver) {
			// 检查用户时候已经创建了MultipartResolver的实例,但是命名不正确
			return resolver;
		}

	}

    /**
     * =============================================================
     * 嵌套配置类DispatcherServletRegistrationConfiguration
     * 1、定义并实例化DispatcherServletRegistrationBean
     * 这个bean的目的是将DispatcherServletConfiguration配置类中实例化的dispatcherServlet bean注册到Servlet容器
     * =============================================================
     */
    // 指定该类为配置类
	@Configuration(proxyBeanMethods = false)
    // 只有在DispatcherServletRegistrationCondition条件类被满足的情况下,这个配置类才生效
	@Conditional(DispatcherServletRegistrationCondition.class)
    // 只有在classpath下存在ServletRegistration类的时候,该配置类才生效
	@ConditionalOnClass(ServletRegistration.class)
    // 实例化WebMvcProperties配置属性类
	@EnableConfigurationProperties(WebMvcProperties.class)
    // 导入DispatcherServletConfiguration配置类
	@Import(DispatcherServletConfiguration.class)
	protected static class DispatcherServletRegistrationConfiguration {

        // 实例化DispatcherServletRegistrationBean bean,并命名为dispatcherServletRegistration
		@Bean(name = DEFAULT_DISPATCHER_SERVLET_REGISTRATION_BEAN_NAME)
        // 只有在名字是dispatcherServlet的DispatcherServlet bean存在时,才生效
		@ConditionalOnBean(value = DispatcherServlet.class, name = DEFAULT_DISPATCHER_SERVLET_BEAN_NAME)
		public DispatcherServletRegistrationBean dispatcherServletRegistration(DispatcherServlet dispatcherServlet,
				WebMvcProperties webMvcProperties, ObjectProvider<MultipartConfigElement> multipartConfig) {
			DispatcherServletRegistrationBean registration = new DispatcherServletRegistrationBean(dispatcherServlet,
					webMvcProperties.getServlet().getPath());
			registration.setName(DEFAULT_DISPATCHER_SERVLET_BEAN_NAME);
			registration.setLoadOnStartup(webMvcProperties.getServlet().getLoadOnStartup());
			multipartConfig.ifAvailable(registration::setMultipartConfig);
			return registration;
		}

	}

	@Order(Ordered.LOWEST_PRECEDENCE - 10)
	private static class DefaultDispatcherServletCondition extends SpringBootCondition {

		@Override
		public ConditionOutcome getMatchOutcome(ConditionContext context, AnnotatedTypeMetadata metadata) {
			ConditionMessage.Builder message = ConditionMessage.forCondition("Default DispatcherServlet");
			ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
			List<String> dispatchServletBeans = Arrays
					.asList(beanFactory.getBeanNamesForType(DispatcherServlet.class, false, false));
			if (dispatchServletBeans.contains(DEFAULT_DISPATCHER_SERVLET_BEAN_NAME)) {
				return ConditionOutcome
						.noMatch(message.found("dispatcher servlet bean").items(DEFAULT_DISPATCHER_SERVLET_BEAN_NAME));
			}
			if (beanFactory.containsBean(DEFAULT_DISPATCHER_SERVLET_BEAN_NAME)) {
				return ConditionOutcome.noMatch(
						message.found("non dispatcher servlet bean").items(DEFAULT_DISPATCHER_SERVLET_BEAN_NAME));
			}
			if (dispatchServletBeans.isEmpty()) {
				return ConditionOutcome.match(message.didNotFind("dispatcher servlet beans").atAll());
			}
			return ConditionOutcome.match(message.found("dispatcher servlet bean", "dispatcher servlet beans")
					.items(Style.QUOTE, dispatchServletBeans)
					.append("and none is named " + DEFAULT_DISPATCHER_SERVLET_BEAN_NAME));
		}

	}

	@Order(Ordered.LOWEST_PRECEDENCE - 10)
	private static class DispatcherServletRegistrationCondition extends SpringBootCondition {

		@Override
		public ConditionOutcome getMatchOutcome(ConditionContext context, AnnotatedTypeMetadata metadata) {
			ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
			ConditionOutcome outcome = checkDefaultDispatcherName(beanFactory);
			if (!outcome.isMatch()) {
				return outcome;
			}
			return checkServletRegistration(beanFactory);
		}

		private ConditionOutcome checkDefaultDispatcherName(ConfigurableListableBeanFactory beanFactory) {
			List<String> servlets = Arrays
					.asList(beanFactory.getBeanNamesForType(DispatcherServlet.class, false, false));
			boolean containsDispatcherBean = beanFactory.containsBean(DEFAULT_DISPATCHER_SERVLET_BEAN_NAME);
			if (containsDispatcherBean && !servlets.contains(DEFAULT_DISPATCHER_SERVLET_BEAN_NAME)) {
				return ConditionOutcome.noMatch(
						startMessage().found("non dispatcher servlet").items(DEFAULT_DISPATCHER_SERVLET_BEAN_NAME));
			}
			return ConditionOutcome.match();
		}

		private ConditionOutcome checkServletRegistration(ConfigurableListableBeanFactory beanFactory) {
			ConditionMessage.Builder message = startMessage();
			List<String> registrations = Arrays
					.asList(beanFactory.getBeanNamesForType(ServletRegistrationBean.class, false, false));
			boolean containsDispatcherRegistrationBean = beanFactory
					.containsBean(DEFAULT_DISPATCHER_SERVLET_REGISTRATION_BEAN_NAME);
			if (registrations.isEmpty()) {
				if (containsDispatcherRegistrationBean) {
					return ConditionOutcome.noMatch(message.found("non servlet registration bean")
							.items(DEFAULT_DISPATCHER_SERVLET_REGISTRATION_BEAN_NAME));
				}
				return ConditionOutcome.match(message.didNotFind("servlet registration bean").atAll());
			}
			if (registrations.contains(DEFAULT_DISPATCHER_SERVLET_REGISTRATION_BEAN_NAME)) {
				return ConditionOutcome.noMatch(message.found("servlet registration bean")
						.items(DEFAULT_DISPATCHER_SERVLET_REGISTRATION_BEAN_NAME));
			}
			if (containsDispatcherRegistrationBean) {
				return ConditionOutcome.noMatch(message.found("non servlet registration bean")
						.items(DEFAULT_DISPATCHER_SERVLET_REGISTRATION_BEAN_NAME));
			}
			return ConditionOutcome.match(message.found("servlet registration beans").items(Style.QUOTE, registrations)
					.append("and none is named " + DEFAULT_DISPATCHER_SERVLET_REGISTRATION_BEAN_NAME));
		}

		private ConditionMessage.Builder startMessage() {
			return ConditionMessage.forCondition("DispatcherServlet Registration");
		}

	}

}

Springboot Web应用中,DispatcherServlet作为一个bean首先被注册到Spring容器中。然后SpringBoot还生成了一个DispatcherServletRegistrationBeanbeanSpring容器中,这个bean负责将DispatcherServletbean注册到Servlet容器中。

2 DispatcherServlet

DispatcherServletWeb应用中的一个Servlet,称作前端控制器。它是一个派发器,匹配请求并按一定的规则将请求派发到对应的处理器上处理,并最终返回结果。

2.1 DispatcherServlet继承关系

下图是DispatcherServlet的继承关系图:
在这里插入图片描述

简单概括DispatcherServlet继承关系为:

DispatcherServlet -> FrameworkServlet -> HttpServletBean -> HttpServlet -> GenericServlet

GenericServlet实现了Servlet接口。

通过类图可以看出,DispatcherServlet通过继承父类,间接实现了Servlet接口,因此其本质上依旧是一个Servlet

2.2 DispatcherServlet初始化过程

转载:SpringMVC 启动流程及相关源码分析

DispatcherServlet类的设计很巧妙,上层父类不同程度的实现了相关接口的部分方法,并留出了相关方法用于子类覆盖,将不变的部分统一实现,将变化的部分通过预留方法用于子类实现。

Servlet的初始化,是通过调用init(ServletConfig config)方法实现的。

通过继承关系可以画出DispatcherServlet初始化调用链:
在这里插入图片描述

上述调用逻辑中比较重要的有三个方法:

  • FrameworkServlet抽象类中的initServletBean()方法
  • FrameworkServlet抽象类中的initWebApplicationContext()方法
  • DispatcherServlet类中的onRefresh()方法

2.2.1 FrameworkServlet抽象类中的initServletBean()

initServletBean()源码:

    @Override
	protected final void initServletBean() throws ServletException {
		getServletContext().log("Initializing Spring " + getClass().getSimpleName() + " '" + getServletName() + "'");
		if (logger.isInfoEnabled()) {
			logger.info("Initializing Servlet '" + getServletName() + "'");
		}
		long startTime = System.currentTimeMillis();

		try {
			this.webApplicationContext = initWebApplicationContext();
			initFrameworkServlet();
		}
		catch (ServletException | RuntimeException ex) {
			logger.error("Context initialization failed", ex);
			throw ex;
		}

		if (logger.isDebugEnabled()) {
			String value = this.enableLoggingRequestDetails ?
					"shown which may lead to unsafe logging of potentially sensitive data" :
					"masked to prevent unsafe logging of potentially sensitive data";
			logger.debug("enableLoggingRequestDetails='" + this.enableLoggingRequestDetails +
					"': request parameters and headers will be " + value);
		}

		if (logger.isInfoEnabled()) {
			logger.info("Completed initialization in " + (System.currentTimeMillis() - startTime) + " ms");
		}
	}

这个方法有final标识,那么FrameworkServlet的子类就不可以再重写了。该方法主要是为了调用initWebApplicationContext()方法,并在前后打印了一些日志信息。

2.2.2 FrameworkServlet抽象类中的initWebApplicationContext()

initWebApplicationContext()源码:

    /**
	 * 为当前Servlet初始化并发布WebApplicationContext。
	 * 委托createWebApplicationContext方法去创建context,可以被子类重写。
	 */    
    protected WebApplicationContext initWebApplicationContext() {
        // 获取由ContextLoaderListener创建的根IoC容器的上下文
		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) {
						// 如果当前存在一个子容器,并且其父容器的引用是null,则将根容器作为它的父容器
						cwac.setParent(rootContext);
					}
                    // 配置并刷新当前的子容器
					configureAndRefreshWebApplicationContext(cwac);
				}
			}
		}
		if (wac == null) {
			// 如果当前应用不存在子容器,则去查找一下
			wac = findWebApplicationContext();
		}
		if (wac == null) {
			// 如果仍旧没有查找到子容器,则创建一个子容器
			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.
			synchronized (this.onRefreshMonitor) {
				// 刷新子容器
                onRefresh(wac);
			}
		}

		if (this.publishContext) {
			// Publish the context as a servlet context attribute.
			String attrName = getServletContextAttributeName();
			getServletContext().setAttribute(attrName, wac);
		}

		return wac;
	}

该方法的主要作用同样是创建一个WebApplicationContext对象,即Ioc容器,这里创建的是特定Servlet拥有的子IoC容器。

Spring中的父子容器的访问特性:父子容器类似于类的继承关系,子类可以访问父类中的成员变量,而父类不可访问子类的成员变量。同样的,子容器可以访问父容器中定义的Bean,但父容器无法访问子容器定义的Bean。

Spring中创建多个Ioc容器,根IoC容器做为全局共享的IoC容器维护Web应用需要共享的Bean,而子IoC容器根据需求的不同,维护不同的Bean,这样能够做到隔离,保证系统的安全性。

下面,查看createWebApplicationContext方法的源码:

    protected WebApplicationContext createWebApplicationContext(@Nullable WebApplicationContext parent) {
		return createWebApplicationContext((ApplicationContext) parent);
	}

    protected WebApplicationContext createWebApplicationContext(@Nullable ApplicationContext parent) {
		Class<?> contextClass = getContextClass();
        // 判断当前contextClass是否是ConfigurableWebApplicationContext的子类
		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");
		}
        // 创建子容器上下文对象
		ConfigurableWebApplicationContext wac =
				(ConfigurableWebApplicationContext) BeanUtils.instantiateClass(contextClass);
        // 设置环境信息
		wac.setEnvironment(getEnvironment());
        // 设置子容器的父容器
		wac.setParent(parent);
        // 设置配置文件的位置信息
		String configLocation = getContextConfigLocation();
		if (configLocation != null) {
			wac.setConfigLocation(configLocation);
		}
        // 配置并刷新子容器
		configureAndRefreshWebApplicationContext(wac);

		return wac;
	}

该方法用于创建一个子IoC容器并将根IoC容器做为其父容器,接着进行配置和刷新操作用于构造相关的Bean
至此,根IoC容器以及相关Servlet子IoC容器已经配置完成,子容器中管理的Bean一般只被该Servlet使用,因此,其中管理的Bean一般是“局部”的,如SpringMVC中需要的各种重要组件,包括ControllerInterceptorConverterExceptionResolver等。

相关关系如下图所示:
在这里插入图片描述

查看configureAndRefreshWebApplicationContext方法:

    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());
		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);
		wac.refresh();
	}

该方法主要是对子容器进行一些信息的配置,最后会调用refresh()方法刷新容器。

回到initWebApplicationContext方法中,当createWebApplicationContext创建子容器之后,最后调用onRefresh方法刷新容器:

        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.
			synchronized (this.onRefreshMonitor) {
				onRefresh(wac);
			}
		}

onRefresh的真正实现是在DispatcherServlet类中,下面是onRefresh源码:

    /**
	 * This implementation calls {@link #initStrategies}.
	 */
	@Override
	protected void onRefresh(ApplicationContext context) {
		initStrategies(context);
	}

	/**
	 * Initialize the strategy objects that this servlet uses.
	 * <p>May be overridden in subclasses in order to initialize further strategy objects.
	 */
	protected void initStrategies(ApplicationContext context) {
		initMultipartResolver(context);
		initLocaleResolver(context);
		initThemeResolver(context);
		initHandlerMappings(context);
		initHandlerAdapters(context);
		initHandlerExceptionResolvers(context);
		initRequestToViewNameTranslator(context);
		initViewResolvers(context);
		initFlashMapManager(context);
	}

onRefresh()方法直接调用了initStrategies()方法。该方法用于初始化创建multipartResovle来支持图片等文件的上传、本地化解析器、主题解析器、HandlerMapping处理器映射器、HandlerAdapter处理器适配器、异常解析器、视图解析器、flashMap管理器,这些组件都是SpringMVC开发中的重要组件,相关组件的初始化创建过程均在此完成。

转载:SpringMVC 启动流程及相关源码分析

2.3 DispatcherServlet请求流程

转载:SpringMVC DispatcherServlet执行流程及源码分析

Spring MVC有四大组件:

  • DispatcherServlet
  • HandlerMapping
  • HandlerAdapter
  • ViewResolver

Spring MVC处理用户请求的过程就是围绕这四大组件进行的。

如下时序图:

[图]…

请求处理流程文字描述如下:

  1. 用户请求发送至DispatcherServlet类。
  2. DispatcherServlet遍历配置的所有HandlerMapping,查找对应的Handler

// TODO

2.3.1 方法执行流程

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ykMs4XUv-1595642843541)(C:\Users\taojie6\AppData\Roaming\Typora\typora-user-images\1594814306943.png)]

上图展示了处理用户请求的方法调用流程:

  1. 首先请求进入Servletservice(ServletRequest req, ServletResponse res)方法。
  2. 实现是GenericServlet类的抽象方法service(ServletRequest req, ServletResponse res)
  3. 最终的具体实现是HttpServlet类的service(ServletRequest req, ServletResponse res)方法。首先将req对象转换为HttpServletRequest类型,将res对象转换为HttpServletResponse类型,然后调用类中的service(HttpServletRequest req, HttpServletResponse resp)方法。根据请求的方法类型,分别调用doGetdoPostdoHead等方法。
  4. 具体的实现是在FrameworkServlet中,最终统一调用的是processRequest方法。在processRequest中,又调用了doService方法,该方法由DispatcherServlet实现。

根据层层分析,可以看出对用户请求的处理主要流程是集中在DispatcherServlet中的doService方法里面。

2.3.2 处理用户请求的流程

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

		// 将框架的一些对象,包括容器的context对象,放入request中,这样就可以很方便的随时拿到它们
		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处理用户请求
			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);
				}
			}
		}
	}

doService()方法主要进行一些参数的设置,并将部分参数放入request请求中,真正执行用户请求并作出响应的方法则为doDispatch()方法。

doDispatch方法源码:

    protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
		// 请求对象
        HttpServletRequest processedRequest = request;
        // HandlerExecutionChain局部变量
		HandlerExecutionChain mappedHandler = null;
        // 判断是否解析了文件类型的数据,如果有最终需要清理
		boolean multipartRequestParsed = false;

		WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);

		try {
            // ModelAndView局部变量
			ModelAndView mv = null;
            // 异常对象
			Exception dispatchException = null;

			try {
                // 检查是否包含文件类型的数据
				processedRequest = checkMultipart(request);
				multipartRequestParsed = (processedRequest != request);

				// (1)从所有的HandlerMapping中搜索获取处理当前请求的HandlerExecutionChain
				mappedHandler = getHandler(processedRequest);
                // 如果HandlerExecutionChain为null,则没有能够进行处理的Handler,抛出异常
				if (mappedHandler == null) {
					noHandlerFound(processedRequest, response);
					return;
				}

				// 根据查到的HandlerExecutionChain对象中的handler,从所有的HandlerAdapter中搜索获取处理请求的HandlerAdapter
                // 如果没找到会抛异常
				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;
					}
				}
                // 按顺序依次执行HandlerInterceptor的preHandle方法
                // 如果任意一个HandlerInterceptor的preHandle方法没有通过,则不继续进行处理
				if (!mappedHandler.applyPreHandle(processedRequest, response)) {
					return;
				}

				// 通过HandlerAdapter执行Handler,处理用户请求
				mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

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

				applyDefaultViewName(processedRequest, mv);
                // 逆序执行HandlerInterceptor的postHandle方法
				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);
			}
            // 处理返回的结果,渲染视图、填充model;如果有异常,渲染异常页面
			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) {
                    // 倒序执行所有HandlerInterceptor的afterCompletion方法
					mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
				}
			}
			else {
				// 如果请求包含文件类型的数据,则进行相关清理工作
				if (multipartRequestParsed) {
					cleanupMultipart(processedRequest);
				}
			}
		}
	}
2.3.2.1 遍历所有HandlerMapping获取HandlerExecutionChain对象

doDispatch(...)方法中,(1)处通过调用getHandler(...),传入的是HttpServletRequest对象,返回一个HandlerExecutionChain对象,源码如下:

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

该方法遍历了开发者配置的所有HandlerMapping类,根据request请求来查找HandlerExecutionChain,如果找到了,返回第一个找到的HandlerExecutionChain

如果没有找到HandlerExecutionChain,则会调用noHandlerFound(...)方法:

    mappedHandler = getHandler(processedRequest);
    if (mappedHandler == null) {
        noHandlerFound(processedRequest, response);
        return;
    }

noHandlerFound(...)源码如下:

    protected void noHandlerFound(HttpServletRequest request, HttpServletResponse response) throws Exception {
		if (pageNotFoundLogger.isWarnEnabled()) {
			pageNotFoundLogger.warn("No mapping for " + request.getMethod() + " " + getRequestUri(request));
		}
		if (this.throwExceptionIfNoHandlerFound) {
			throw new NoHandlerFoundException(request.getMethod(), getRequestUri(request),
					new ServletServerHttpRequest(request).getHeaders());
		}
		else {
			response.sendError(HttpServletResponse.SC_NOT_FOUND);
		}
	}

如果没有找到对应的HandlerExecutionChain,则会抛出异常NoHandlerFoundException

2.3.2.2 获取HandlerAdapter对象

如果找到了HandlerExecutionChain对象,接下来会调用getHandlerAdapter(...)方法,传入HandlerExecutionChain对象中的handler对象,得到能够支持这个handlerHandlerAdapter对象,源码如下:

    protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
		if (this.handlerAdapters != null) {
			for (HandlerAdapter adapter : this.handlerAdapters) {
				if (adapter.supports(handler)) {
					return adapter;
				}
			}
		}
		throw new ServletException("No adapter for handler [" + handler +
				"]: The DispatcherServlet configuration needs to include a HandlerAdapter that supports this handler");
	}

该方法会遍历所有的HandlerAdapter,调用每个Adaptersupports(...)方法,如果支持,就会返回这个HandlerAdapter。如果遍历完了还没找到,就会抛出ServletException异常。

2.3.2.3 调用HandlerInteceptor的preHandle方法

找到HandlerAdapter之后,接下来会先调用HandlerExecutionChainapplyPreHandle(...)方法:

    if (!mappedHandler.applyPreHandle(processedRequest, response)) {
        return;
    }

该方法里面,会去调用所有已配置的HandlerInterceptorpreHandle方法,源码如下:

    boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception {
		HandlerInterceptor[] interceptors = getInterceptors();
		if (!ObjectUtils.isEmpty(interceptors)) {
			for (int i = 0; i < interceptors.length; i++) {
				HandlerInterceptor interceptor = interceptors[i];
				if (!interceptor.preHandle(request, response, this.handler)) {
					triggerAfterCompletion(request, response, null);
					return false;
				}
				this.interceptorIndex = i;
			}
		}
		return true;
	}

改方法会按照顺序依次调用HandlerInterceptorpreHandle()方法,但当任一HandlerInterceptorpreHandle()方法返回了false就不再继续执行其他HandlerInterceptorpreHandle()方法,而是直接跳转执行triggerAfterCompletion()方法:

    void triggerAfterCompletion(HttpServletRequest request, HttpServletResponse response, @Nullable Exception ex)
			throws Exception {

		HandlerInterceptor[] interceptors = getInterceptors();
		if (!ObjectUtils.isEmpty(interceptors)) {
			for (int i = this.interceptorIndex; i >= 0; i--) {
				HandlerInterceptor interceptor = interceptors[i];
				try {
					interceptor.afterCompletion(request, response, this.handler, ex);
				}
				catch (Throwable ex2) {
					logger.error("HandlerInterceptor.afterCompletion threw exception", ex2);
				}
			}
		}
	}

这里遍历的下标为interceptorIndex,该变量在前一个方法applyPreHandle()方法中赋值,如果preHandle()方法返回true该变量加1

因此该方法会逆序执行所有preHandle()方法返回了trueHandlerInterceptorafterCompletion()方法。

2.3.2.4 处理请求
  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值