SpringMVC源码解析

xml配置文件版

0. 准备阶段

maven springMVC工程搭建

web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee"
         xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" id="WebApp_ID" version="3.0">

  <!-- spring主配置文件位置 -->
  <context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>classpath:spring-config/spring-*.xml</param-value>
  </context-param>

  <!-- 配置监听器 -->
  <listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
  </listener>

  <!-- 配置中央调度器 -->
  <servlet>
    <servlet-name>springMVC</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <init-param>
      <param-name>contextConfigLocation</param-name>
      <param-value>classpath:spring-config/springmvc-config.xml</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
  </servlet>
  <servlet-mapping>
    <servlet-name>springMVC</servlet-name>
    <url-pattern>/</url-pattern>
  </servlet-mapping>

  <!-- 配置字符集过滤器 -->
  <filter>
    <filter-name>characterEncodingFilter</filter-name>
    <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
    <init-param>
      <param-name>encoding</param-name>
      <param-value>utf-8</param-value>
    </init-param>
    <init-param>
      <param-name>forceEncoding</param-name>
      <param-value>true</param-value>
    </init-param>
  </filter>
  <filter-mapping>
    <filter-name>characterEncodingFilter</filter-name>
    <url-pattern>/*</url-pattern>
  </filter-mapping>
</web-app>

springmvc-config.xml

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:mvc="http://www.springframework.org/schema/mvc"
       xmlns:tx="http://www.springframework.org/schema/tx"
       xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd
		http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
		http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.0.xsd
		http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd
		http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd">

    <!-- 静态资源处理器 -->
    <mvc:default-servlet-handler/>

    <!-- 配置注解驱动 -->
    <mvc:annotation-driven/>

    <!-- controller扫描器 -->
    <context:component-scan base-package="com.tca.springmvc.learning.controller"/>
</beans>

controller

/**
 * @author zhouan
 * @Date 2021/6/7
 */
@Controller
@RequestMapping("/hello")
public class HelloController {

    @GetMapping("/test")
    @ResponseBody
    public String test() {
        return String.valueOf(System.currentTimeMillis());
    }

    @RequestMapping("/message")
    @ResponseBody
    public String message(@RequestBody JSONObject request) {
        System.out.println("收到消息: " + request.toJSONString());
        return "ok";
    }
}

1.java web基础

1.1 启动原理

1.web容器(如tomcat)启动时, 会根据tomcat的配置文件读取项目的web.xml配置文件, web.xml配置文件中主要涉及的标签有: 
<context-param>、<listener>、<fileter>、<servlet>
加载的顺序是: <context-param>、<listener>、<fileter>、<servlet>
2.web容器启动时(如tomcat), 首先加载依赖的jar, 然后读取web.xml文件, 创建ServletContext, 容器会将context-param的配置以key-value键值对形式传给servletContext, 并且实例化<listener>标签中配置的类, 然后初始化Filter和Servlet
3.我们在springmvc工程中配置的<listener>为org.springframework.web.context.ContextLoaderListener, 它实现了ServletContextListener接口, 这个接口用于监听web容器的开启和关闭, 并有对应方法进行回调

1.2 ServletContextListener

public interface ServletContextListener extends EventListener {
	/**
	 ** Notification that the web application initialization
	 ** process is starting.
	 ** All ServletContextListeners are notified of context
	 ** initialization before any filter or servlet in the web
	 ** application is initialized.
	 */
    public void contextInitialized ( ServletContextEvent sce );

	/**
	 ** Notification that the servlet context is about to be shut down.
	 ** All servlets and filters have been destroy()ed before any
	 ** ServletContextListeners are notified of context
	 ** destruction.
	 */
    public void contextDestroyed ( ServletContextEvent sce );
}
这个接口提供了两个方法,分别用来监听web容器启动和关闭进行回调,可以看到:contextInitialized的执行顺序优先于filter和servlet的初始化!

2.ContextLoaderListener

public class ContextLoaderListener extends ContextLoader implements ServletContextListener {

	public ContextLoaderListener() {
	}

	public ContextLoaderListener(WebApplicationContext context) {
		super(context);
	}

	/**
	 * Initialize the root web application context.
	 */
	@Override
	public void contextInitialized(ServletContextEvent event) {
		initWebApplicationContext(event.getServletContext());
	}

	/**
	 * Close the root web application context.
	 */
	@Override
	public void contextDestroyed(ServletContextEvent event) {
		closeWebApplicationContext(event.getServletContext());
		ContextCleanupListener.cleanupAttributes(event.getServletContext());
	}

}

2.1ContextLoaderListener#contextInitialized(ServletContextEvent event)

@Override
public void contextInitialized(ServletContextEvent event) {
    initWebApplicationContext(event.getServletContext());
}

2.2 ContextLoader#initWebApplicationContext(ServletContext servletContext)

/**
	 * Initialize Spring's web application context for the given servlet context,
	 * using the application context provided at construction time, or creating a new one
	 * according to the "{@link #CONTEXT_CLASS_PARAM contextClass}" and
	 * "{@link #CONFIG_LOCATION_PARAM contextConfigLocation}" context-params.
	 * @param servletContext current servlet context
	 * @return the new WebApplicationContext
	 * @see #ContextLoader(WebApplicationContext)
	 * @see #CONTEXT_CLASS_PARAM
	 * @see #CONFIG_LOCATION_PARAM
	 */
public WebApplicationContext initWebApplicationContext(ServletContext servletContext) {
    // 1.判断servletContext中是否已有ROOT
    if (servletContext.getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE) != null) {
        throw new IllegalStateException(
            "Cannot initialize context because there is already a root application context present - " +
            "check whether you have multiple ContextLoader* definitions in your web.xml!");
    }

    Log logger = LogFactory.getLog(ContextLoader.class);
    servletContext.log("Initializing Spring root WebApplicationContext");
    if (logger.isInfoEnabled()) {
        logger.info("Root WebApplicationContext: initialization started");
    }
    long startTime = System.currentTimeMillis();

    try {
        // Store context in local instance variable, to guarantee that
        // it is available on ServletContext shutdown.
        // 2.判断是否有WebApplicationContext实例, 如果没有需要创建
        if (this.context == null) {
            // 3.创建WebApplicationContext, 这里是 XmlWebApplicationContext, 这里仅仅是创建父容器, 并没有进行配置和启动
            this.context = createWebApplicationContext(servletContext);
        }
        if (this.context instanceof ConfigurableWebApplicationContext) {
            // 4.进入
            ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext) this.context;
            // 5.容器如果没有启动
            if (!cwac.isActive()) {
                // The context has not yet been refreshed -> provide services such as
                // setting the parent context, setting the application context id, etc
                // 6.父容器为null
                if (cwac.getParent() == null) {
                    // The context instance was injected without an explicit parent ->
                    // determine parent for root web application context, if any.
                    // 7.设置父容器为null
                    ApplicationContext parent = loadParentContext(servletContext);
                    cwac.setParent(parent);
                }
                // 8.封装容器XmlWebApplicationContext, 并启动容器refresh()方法
                // 这个方法会对父容器 XmlWebApplicationContext 进行配置并启动, 配置中包括读取ServletContext的初始化参数:contextConfigLocation, 这个参数对应的value, 在web.xml文件中的开头就进行了配置: <context-param>, value为: classpath:spring-config/spring-*.xml, 即为父容器的主配置文件!!!
                configureAndRefreshWebApplicationContext(cwac, servletContext);
            }
        }
        // 9.将spring容器设为servletContext的ROOT属性
        servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, this.context);
	    // 10.这里的ClassLoader是 WebAppClassLoader
        ClassLoader ccl = Thread.currentThread().getContextClassLoader();
        if (ccl == ContextLoader.class.getClassLoader()) {
            currentContext = this.context;
        }
        else if (ccl != null) {
            currentContextPerThread.put(ccl, this.context);
        }

        if (logger.isDebugEnabled()) {
            logger.debug("Published root WebApplicationContext as ServletContext attribute with name [" +
                         WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE + "]");
        }
        if (logger.isInfoEnabled()) {
            long elapsedTime = System.currentTimeMillis() - startTime;
            logger.info("Root WebApplicationContext: initialization completed in " + elapsedTime + " ms");
        }
		// 11.返回当前容器
        return this.context;
    }
    catch (RuntimeException ex) {
        logger.error("Context initialization failed", ex);
        servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, ex);
        throw ex;
    }
    catch (Error err) {
        logger.error("Context initialization failed", err);
        servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, err);
        throw err;
    }
}

总结

1.web容器(如tomcat)启动时, 创建ServletContext对象, 作为web容器Servlet上下文, 同时去加载web.xml文件
2.web.xml文件中配置了<listener>监听器, 其实现类为ContextLoaderListener, 用于监听web容器的开启和关闭, 因此web容器启动时会回调ContextLoaderListener#initWebApplicationContext(ServletContext servletContext)方法, 该方法用于创建一个XmlWebApplicationContext的spring-web容器, 并将其作为ServletContext的一个属性, 属性为ROOT

问题

1.父容器的作用是什么? 为什么需要设置父子容器?

3.FrameworkServlet

想要了解另一个核心类DispatcherServlet,需要先熟悉其父类FrameworkServlet

3.1 结构图

可以看到,其继承了HttpServletBean,同时实现了ApplicationContextAware接口

3.2 初始化

3.2.1 流程

step1:web容器在实例化servlet时会调用Servlet的init(ServletConfig)方法,由Servlet子类GenericServlet实现了该方法,因而最终会调用GenericServlet.init(ServletConfig)方法。

GenericServlet#init(ServletConfig)

public void init(ServletConfig config) throws ServletException {
	this.config = config;
	this.init();
}

step2:调用init()方法,init()方法由GenericServlet的子类HttpServletBean实现,实际上是执行了HttpServletBean.init()方法

HttpServletBean#init()

@Override
public final void init() throws ServletException {
    if (logger.isDebugEnabled()) {
        logger.debug("Initializing servlet '" + getServletName() + "'");
    }

    // Set bean properties from init parameters.
    try {
        // 1.获取web.xml中 DispatcherServlet的<init-param>参数配置, contextConfigLocation -- classpath:spring-config/springmvc-config.xml
        PropertyValues pvs = new ServletConfigPropertyValues(getServletConfig(), this.requiredProperties);
        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) {
        if (logger.isErrorEnabled()) {
            logger.error("Failed to set bean properties on servlet '" + getServletName() + "'", ex);
        }
        throw ex;
    }

    // Let subclasses do whatever initialization they like.
    // 2.调用子类方法
    initServletBean();

    if (logger.isDebugEnabled()) {
        logger.debug("Servlet '" + getServletName() + "' configured successfully");
    }
}

step3 上述中调用了HttpServletBean.init()方法,这个方法中调用了initServletBean()方法,这个方法由子类FrameworkServlet实现

FrameworkServlet#initServletBean()

@Override
protected final void initServletBean() throws ServletException {
    getServletContext().log("Initializing Spring FrameworkServlet '" + getServletName() + "'");
    if (this.logger.isInfoEnabled()) {
        this.logger.info("FrameworkServlet '" + getServletName() + "': initialization started");
    }
    long startTime = System.currentTimeMillis();

    try {
        // 1.创建并初始化子容器
        this.webApplicationContext = initWebApplicationContext();
        // 2.空实现
        initFrameworkServlet();
    }
    catch (ServletException ex) {
        this.logger.error("Context initialization failed", ex);
        throw ex;
    }
    catch (RuntimeException ex) {
        this.logger.error("Context initialization failed", ex);
        throw ex;
    }

    if (this.logger.isInfoEnabled()) {
        long elapsedTime = System.currentTimeMillis() - startTime;
        this.logger.info("FrameworkServlet '" + getServletName() + "': initialization completed in " +
                         elapsedTime + " ms");
    }
}

FrameworkServlet#initWebApplicationContext()

protected WebApplicationContext initWebApplicationContext() {
    // 1.获取Root的 XmlWebApplicationContext, 这里是从servletContext中获取ContextLoaderListener中创建的 webApplicationContext
    WebApplicationContext rootContext =
        WebApplicationContextUtils.getWebApplicationContext(getServletContext());
    WebApplicationContext wac = null;
    // 2.为空, 跳过
    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
        // 3.wac == null, 子容器没有创建
        wac = findWebApplicationContext();
    }
    if (wac == null) {
        // No context instance is defined for this servlet -> create a local one
        // 4.创建子容器, 并启动
        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.
        onRefresh(wac);
    }
	
    // 5.进入
    if (this.publishContext) {
        // Publish the context as a servlet context attribute.
        // 6.创建完子容器后, 将子容器也存储到servletContext的属性中
        // (org.springframework.web.servlet.FrameworkServlet.CONTEXT.springMVC --> 子容器)
        // ("org.springframework.web.context.WebApplicationContext.ROOT" -> 父容器)
        String attrName = getServletContextAttributeName();
        getServletContext().setAttribute(attrName, wac);
        if (this.logger.isDebugEnabled()) {
            this.logger.debug("Published WebApplicationContext of servlet '" + getServletName() +
                              "' as ServletContext attribute with name [" + attrName + "]");
        }
    }

    return wac;
}

FrameworkServlet#createWebApplicationContext(ApplicationContext parent)

/**
 * Instantiate the WebApplicationContext for this servlet, either a default
 * {@link org.springframework.web.context.support.XmlWebApplicationContext}
 * or a {@link #setContextClass custom context class}, if set.
 * <p>This implementation expects custom contexts to implement the
 * {@link org.springframework.web.context.ConfigurableWebApplicationContext}
 * interface. Can be overridden in subclasses.
 * <p>Do not forget to register this servlet instance as application listener on the
 * created context (for triggering its {@link #onRefresh callback}, and to call
 * {@link org.springframework.context.ConfigurableApplicationContext#refresh()}
 * before returning the context instance.
 * @param parent the parent ApplicationContext to use, or {@code null} if none
 * @return the WebApplicationContext for this servlet
 * @see org.springframework.web.context.support.XmlWebApplicationContext
 * 创建子容器 webApplicationContext, 跟当前FrameworkServlet(DispatcherServlet)绑定
 * 父容器 --> servletContext中存储
 * 子容器 --> FrameworkServlet(DispatcherServlet)中存储 servletContext中存储
 */
protected WebApplicationContext createWebApplicationContext(ApplicationContext parent) {
    // 1.contextClass == org.springframework.web.context.support.XmlWebApplicationContext
    Class<?> contextClass = getContextClass();
    if (this.logger.isDebugEnabled()) {
        this.logger.debug("Servlet with name '" + getServletName() +
                          "' will try to create custom WebApplicationContext context of class '" +
                          contextClass.getName() + "'" + ", using parent context [" + parent + "]");
    }
    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");
    }
    // 2.实例化 XmlWebApplicationContext
    ConfigurableWebApplicationContext wac =
        (ConfigurableWebApplicationContext) BeanUtils.instantiateClass(contextClass);

    wac.setEnvironment(getEnvironment());
    // 3.设置当前 XmlWebApplicationContext的父容器为 ROOT(ContextLoaderListener创建的容器, 并存储到servletContext中的)
    wac.setParent(parent);
    // 4.设置配置文件路径, 这里的路径是web.xml文件中DispatcherServlet中, init-param中配置的变量 -- contextConfigLocation, 这里是: classpath:spring-config/springmvc-config.xml
    wac.setConfigLocation(getContextConfigLocation());
	// 5.配置并启动子容器
    configureAndRefreshWebApplicationContext(wac);

    return wac;
}

FrameworkServlet#configureAndRefreshWebApplicationContext(ConfigurableWebApplicationContext wac)

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 {
            // 1.生成容器id: org.springframework.web.context.WebApplicationContext:/springMVC
            wac.setId(ConfigurableWebApplicationContext.APPLICATION_CONTEXT_ID_PREFIX +
                      ObjectUtils.getDisplayString(getServletContext().getContextPath()) + '/' + getServletName());
        }
    }
    // 2.设置servletContext
    wac.setServletContext(getServletContext());
    // 3.设置servletConfig
    wac.setServletConfig(getServletConfig());
    // 4.设置namespace
    wac.setNamespace(getNamespace());
    // 5.添加容器监听器, 这个监听器很重要, 容器启动完成后会发布refresh事件, 会被ContextRefreshListener监听
    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);
    // 6.启动容器
    wac.refresh();
}

3.2.2 回调

上述,创建完子容器之后,添加了监听器new SourceFilteringListener(wac, new ContextRefreshListener())监听容器refresh,容器启动时会回调ContextRefreshListener的onApplicationEvent(ContextRefreshedEvent event)方法

/**
	 * ApplicationListener endpoint that receives events from this servlet's WebApplicationContext
	 * only, delegating to {@code onApplicationEvent} on the FrameworkServlet instance.
	 */
private class ContextRefreshListener implements ApplicationListener<ContextRefreshedEvent> {

    @Override
    public void onApplicationEvent(ContextRefreshedEvent event) {
        // 调用FrameworkServlet#onApplicationEvent(event)
        FrameworkServlet.this.onApplicationEvent(event);
    }
}

FrameworkServlet#onApplicationEvent(ContextRefreshedEvent event)

public void onApplicationEvent(ContextRefreshedEvent event) {
    this.refreshEventReceived = true;
    // 这里 onRefresh(ApplicationContext context) 被子类DispatcherServlet重写, 调用的是子类DispatcherServlet的onRefresh(ApplicationContext context)方法
    onRefresh(event.getApplicationContext());
}

总结

web容器启动时, 会加载并初始化web.xml文件中配置的<servlet>, 这里只有核心类DispatcherServlet, 继承了FrameworkServlet, 初始化FrameworkServlet时会创建子spring web容器XmlWebApplicationContext, 创建时会添加监听器ContextRefreshListener, 所以创建完成时回调其onApplicationEvent(ContextRefreshedEvent event)方法, 该方法用于初始化DispatcherServlet相关组件!

4.DispatcherServlet

4.1 初始化

综上,子容器XmlWebApplicationContext启动时,发布ContextRefreshedEvent事件,被已经添加的ContextRefreshListener监听,回调其onApplicationEvent(ContextRefreshedEvent event)方法,这个方法中调用了DispatcherServlet的onRefresh(ApplicationContext context)方法

DispatcherServlet#onRefresh(ApplicationContext context)

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

DispatcherServlet#initStrategies(ApplicationContext context)

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

initMultipartResolver(ApplicationContext context)

/**
 * Initialize the MultipartResolver used by this class.
 * <p>If no bean is defined with the given name in the BeanFactory for this namespace,
 * no multipart handling is provided.
 */
private void initMultipartResolver(ApplicationContext context) {
    try {
        this.multipartResolver = context.getBean(MULTIPART_RESOLVER_BEAN_NAME, MultipartResolver.class);
        if (logger.isDebugEnabled()) {
            logger.debug("Using MultipartResolver [" + this.multipartResolver + "]");
        }
    }
    catch (NoSuchBeanDefinitionException ex) {
        // Default is no multipart resolver.
        this.multipartResolver = null;
        if (logger.isDebugEnabled()) {
            logger.debug("Unable to locate MultipartResolver with name '" + MULTIPART_RESOLVER_BEAN_NAME +
                         "': no multipart request handling provided");
        }
    }
}

初始化MultipartResolver, 用于处理文件上传, 这个是可配置的, 如果未配置, 为空

initLocaleResolver(ApplicationContext context)

/**
 * Initialize the LocaleResolver used by this class.
 * <p>If no bean is defined with the given name in the BeanFactory for this namespace,
 * we default to AcceptHeaderLocaleResolver.
 */
private void initLocaleResolver(ApplicationContext context) {
    try {
        this.localeResolver = context.getBean(LOCALE_RESOLVER_BEAN_NAME, LocaleResolver.class);
        if (logger.isDebugEnabled()) {
            logger.debug("Using LocaleResolver [" + this.localeResolver + "]");
        }
    }
    catch (NoSuchBeanDefinitionException ex) {
        // We need to use the default.
        // 使用默认的LocaleResolver
        this.localeResolver = getDefaultStrategy(context, LocaleResolver.class);
        if (logger.isDebugEnabled()) {
            logger.debug("Unable to locate LocaleResolver with name '" + LOCALE_RESOLVER_BEAN_NAME +
                         "': using default [" + this.localeResolver + "]");
        }
    }
}

初始化LocaleResolver,如果没有配置,使用默认的

initThemeResolver(ApplicationContext context)

/**
 * Initialize the ThemeResolver used by this class.
 * <p>If no bean is defined with the given name in the BeanFactory for this namespace,
 * we default to a FixedThemeResolver.
 */
private void initThemeResolver(ApplicationContext context) {
    try {
        this.themeResolver = context.getBean(THEME_RESOLVER_BEAN_NAME, ThemeResolver.class);
        if (logger.isDebugEnabled()) {
            logger.debug("Using ThemeResolver [" + this.themeResolver + "]");
        }
    }
    catch (NoSuchBeanDefinitionException ex) {
        // We need to use the default.
        // 使用默认的ThemeResolver
        this.themeResolver = getDefaultStrategy(context, ThemeResolver.class);
        if (logger.isDebugEnabled()) {
            logger.debug("Unable to locate ThemeResolver with name '" + THEME_RESOLVER_BEAN_NAME +
                         "': using default [" + this.themeResolver + "]");
        }
    }
}

初始化ThemeResolver,如果没有配置,使用默认的

initHandlerMappings(ApplicationContext context)

/**
 * Initialize the HandlerMappings used by this class.
 * <p>If no HandlerMapping beans are defined in the BeanFactory for this namespace,
 * we default to BeanNameUrlHandlerMapping.
 */
private void initHandlerMappings(ApplicationContext context) {
    this.handlerMappings = null;

    if (this.detectAllHandlerMappings) {
        // Find all HandlerMappings in the ApplicationContext, including ancestor contexts.
        // 1.从子容器中获取所有的HandlerMapping, 这里有3个
        // org.springframework.web.servlet.handler.SimpleUrlHandlerMapping
        // org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping
        // org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping 
        Map<String, HandlerMapping> matchingBeans =
            BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerMapping.class, true, false);
        if (!matchingBeans.isEmpty()) {
            this.handlerMappings = new ArrayList<HandlerMapping>(matchingBeans.values());
            // We keep HandlerMappings in sorted order.
            // 2.排序handlerMapping
            // RequestMappingHandlerMapping、BeanNameUrlHandlerMapping、SimpleUrlHandlerMapping
            AnnotationAwareOrderComparator.sort(this.handlerMappings);
        }
    }
    else {
        try {
            HandlerMapping hm = context.getBean(HANDLER_MAPPING_BEAN_NAME, HandlerMapping.class);
            this.handlerMappings = Collections.singletonList(hm);
        }
        catch (NoSuchBeanDefinitionException ex) {
            // Ignore, we'll add a default HandlerMapping later.
        }
    }

    // Ensure we have at least one HandlerMapping, by registering
    // a default HandlerMapping if no other mappings are found.
    if (this.handlerMappings == null) {
        this.handlerMappings = getDefaultStrategies(context, HandlerMapping.class);
        if (logger.isDebugEnabled()) {
            logger.debug("No HandlerMappings found in servlet '" + getServletName() + "': using default");
        }
    }
}

从容器中获取所有HandlerMapping处理器,并排序,目前有三个,顺序为:RequestMappingHandlerMapping、BeanNameUrlHandlerMapping、SimpleUrlHandlerMapping

initHandlerAdapters(ApplicationContext context)

/**
 * Initialize the HandlerAdapters used by this class.
 * <p>If no HandlerAdapter beans are defined in the BeanFactory for this namespace,
 * we default to SimpleControllerHandlerAdapter.
 */
private void initHandlerAdapters(ApplicationContext context) {
    this.handlerAdapters = null;

    if (this.detectAllHandlerAdapters) {
        // Find all HandlerAdapters in the ApplicationContext, including ancestor contexts.
        // 1.从子容器中获取所有HandlerAdapter, 这里有三个:
        // org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter
        // org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter 
        // org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter
        Map<String, HandlerAdapter> matchingBeans =
            BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerAdapter.class, true, false);
        if (!matchingBeans.isEmpty()) {
            this.handlerAdapters = new ArrayList<HandlerAdapter>(matchingBeans.values());
            // We keep HandlerAdapters in sorted order.
            // 2.排序HandlerAdapter
            // HttpRequestHandlerAdapter、SimpleControllerHandlerAdapter、RequestMappingHandlerAdapter
            AnnotationAwareOrderComparator.sort(this.handlerAdapters);
        }
    }
    else {
        try {
            HandlerAdapter ha = context.getBean(HANDLER_ADAPTER_BEAN_NAME, HandlerAdapter.class);
            this.handlerAdapters = Collections.singletonList(ha);
        }
        catch (NoSuchBeanDefinitionException ex) {
            // Ignore, we'll add a default HandlerAdapter later.
        }
    }

    // Ensure we have at least some HandlerAdapters, by registering
    // default HandlerAdapters if no other adapters are found.
    if (this.handlerAdapters == null) {
        this.handlerAdapters = getDefaultStrategies(context, HandlerAdapter.class);
        if (logger.isDebugEnabled()) {
            logger.debug("No HandlerAdapters found in servlet '" + getServletName() + "': using default");
        }
    }
}

从容器中获取所有HandlerAdapter处理器,并排序,目前有三个,顺序为:HttpRequestHandlerAdapter、SimpleControllerHandlerAdapter、RequestMappingHandlerAdapter

initHandlerExceptionResolvers(ApplicationContext context)

/**
 * Initialize the HandlerExceptionResolver used by this class.
 * <p>If no bean is defined with the given name in the BeanFactory for this namespace,
 * we default to no exception resolver.
 */
private void initHandlerExceptionResolvers(ApplicationContext context) {
    this.handlerExceptionResolvers = null;

    if (this.detectAllHandlerExceptionResolvers) {
        // Find all HandlerExceptionResolvers in the ApplicationContext, including ancestor contexts.
        // 1.从子容器中获取所有 HandlerExceptionResolver, 这里找到3个:
        // org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver
        // org.springframework.web.servlet.mvc.annotation.ResponseStatusExceptionResolver 
        // org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver 
        Map<String, HandlerExceptionResolver> matchingBeans = BeanFactoryUtils
            .beansOfTypeIncludingAncestors(context, HandlerExceptionResolver.class, true, false);
        if (!matchingBeans.isEmpty()) {
            this.handlerExceptionResolvers = new ArrayList<HandlerExceptionResolver>(matchingBeans.values());
            // We keep HandlerExceptionResolvers in sorted order.
            // 2.排序HandlerExceptionResolver: 
            // ExceptionHandlerExceptionResolver、ResponseStatusExceptionResolver、DefaultHandlerExceptionResolver
            AnnotationAwareOrderComparator.sort(this.handlerExceptionResolvers);
        }
    }
    else {
        try {
            HandlerExceptionResolver her =
                context.getBean(HANDLER_EXCEPTION_RESOLVER_BEAN_NAME, HandlerExceptionResolver.class);
            this.handlerExceptionResolvers = Collections.singletonList(her);
        }
        catch (NoSuchBeanDefinitionException ex) {
            // Ignore, no HandlerExceptionResolver is fine too.
        }
    }

    // Ensure we have at least some HandlerExceptionResolvers, by registering
    // default HandlerExceptionResolvers if no other resolvers are found.
    if (this.handlerExceptionResolvers == null) {
        this.handlerExceptionResolvers = getDefaultStrategies(context, HandlerExceptionResolver.class);
        if (logger.isDebugEnabled()) {
            logger.debug("No HandlerExceptionResolvers found in servlet '" + getServletName() + "': using default");
        }
    }
}

从容器中获取所有HandlerExceptionResolver处理器,并排序,目前有三个,顺序为:ExceptionHandlerExceptionResolver、ResponseStatusExceptionResolver、DefaultHandlerExceptionResolver

initRequestToViewNameTranslator(ApplicationContext context)

/**
 * Initialize the RequestToViewNameTranslator used by this servlet instance.
 * <p>If no implementation is configured then we default to DefaultRequestToViewNameTranslator.
 */
private void initRequestToViewNameTranslator(ApplicationContext context) {
    try {
        this.viewNameTranslator =
            context.getBean(REQUEST_TO_VIEW_NAME_TRANSLATOR_BEAN_NAME, RequestToViewNameTranslator.class);
        if (logger.isDebugEnabled()) {
            logger.debug("Using RequestToViewNameTranslator [" + this.viewNameTranslator + "]");
        }
    }
    catch (NoSuchBeanDefinitionException ex) {
        // We need to use the default.
        this.viewNameTranslator = getDefaultStrategy(context, RequestToViewNameTranslator.class);
        if (logger.isDebugEnabled()) {
            logger.debug("Unable to locate RequestToViewNameTranslator with name '" +
                         REQUEST_TO_VIEW_NAME_TRANSLATOR_BEAN_NAME + "': using default [" + this.viewNameTranslator +
                         "]");
        }
    }
}

初始化RequestToViewNameTranslator,如果没有配置,使用默认的

initViewResolvers(ApplicationContext context)

/**
 * Initialize the ViewResolvers used by this class.
 * <p>If no ViewResolver beans are defined in the BeanFactory for this
 * namespace, we default to InternalResourceViewResolver.
 */
private void initViewResolvers(ApplicationContext context) {
    this.viewResolvers = null;

    if (this.detectAllViewResolvers) {
        // Find all ViewResolvers in the ApplicationContext, including ancestor contexts.
        // 1.从子容器中获取所有ViewResolver, 没有获取到
        Map<String, ViewResolver> matchingBeans =
            BeanFactoryUtils.beansOfTypeIncludingAncestors(context, ViewResolver.class, true, false);
        if (!matchingBeans.isEmpty()) {
            this.viewResolvers = new ArrayList<ViewResolver>(matchingBeans.values());
            // We keep ViewResolvers in sorted order.
            AnnotationAwareOrderComparator.sort(this.viewResolvers);
        }
    }
    else {
        try {
            ViewResolver vr = context.getBean(VIEW_RESOLVER_BEAN_NAME, ViewResolver.class);
            this.viewResolvers = Collections.singletonList(vr);
        }
        catch (NoSuchBeanDefinitionException ex) {
            // Ignore, we'll add a default ViewResolver later.
        }
    }

    // Ensure we have at least one ViewResolver, by registering
    // a default ViewResolver if no other resolvers are found.
    if (this.viewResolvers == null) {
        // 2.使用默认的ViewResolver
        this.viewResolvers = getDefaultStrategies(context, ViewResolver.class);
        if (logger.isDebugEnabled()) {
            logger.debug("No ViewResolvers found in servlet '" + getServletName() + "': using default");
        }
    }
}

初始化ViewResolver,如果没有配置,使用默认的

initFlashMapManager(ApplicationContext context)

/**
 * Initialize the {@link FlashMapManager} used by this servlet instance.
 * <p>If no implementation is configured then we default to
 * {@code org.springframework.web.servlet.support.DefaultFlashMapManager}.
 */
private void initFlashMapManager(ApplicationContext context) {
    try {
        this.flashMapManager = context.getBean(FLASH_MAP_MANAGER_BEAN_NAME, FlashMapManager.class);
        if (logger.isDebugEnabled()) {
            logger.debug("Using FlashMapManager [" + this.flashMapManager + "]");
        }
    }
    catch (NoSuchBeanDefinitionException ex) {
        // We need to use the default.
        this.flashMapManager = getDefaultStrategy(context, FlashMapManager.class);
        if (logger.isDebugEnabled()) {
            logger.debug("Unable to locate FlashMapManager with name '" +
                         FLASH_MAP_MANAGER_BEAN_NAME + "': using default [" + this.flashMapManager + "]");
        }
    }
}

初始化FlashMapManager,如果没有配置,使用默认的

总结

这里主要初始化DispatcherServlet的相关组件, 其中最重要的组件有: HandlerMapping、 HandlerAdapter

4.2 建立Map<url, controller>关系

综上,我们从容器中获取所有的HandlerMapping对象时,会获取到其中的BeanNameUrlHandlerMapping、SimpleUrlHandlerMapping和RequestMappingHandlerMapping,这个类继承了AbstractDetectingUrlHandlerMapping,AbstractDetectingUrlHandlerMapping继承了AbstractUrlHandlerMapping,AbstractUrlHandlerMapping继承了WebApplicationObjectSupport,WebApplicationObjectSupport继承了ApplicationObjectSupport,ApplicationObjectSupport实现了ApplicationContextAware接口

即:HandlerMapping实例间接实现了ApplicationContextAware接口

4.2.1 SimpleUrlHandlerMapping

4.2.1.1 结构图

根据[@Spring源码,在bean的创建和初始化过程中,会先后八次调用BeanPostProcessor,在属性注入之后,会第七次调用BeanPostProcessor,执行部分Aware回调接口,这里会回调其父类ApplicationObjectSupport的setApplicationContext(ApplicationContext](/Spring源码,在bean的创建和初始化过程中,会先后八次调用BeanPostProcessor,在属性注入之后,会第七次调用BeanPostProcessor,执行部分Aware回调接口,这里会回调其父类ApplicationObjectSupport的setApplicationContext(ApplicationContext) context)方法

4.3.1.2 ApplicationObjectSupport#setApplicationContext(ApplicationContext context)
@Override
public final void setApplicationContext(ApplicationContext context) throws BeansException {
    if (context == null && !isContextRequired()) {
        // Reset internal context state.
        this.applicationContext = null;
        this.messageSourceAccessor = null;
    }
    else if (this.applicationContext == null) {
        // Initialize with passed-in context.
        if (!requiredContextClass().isInstance(context)) {
            throw new ApplicationContextException(
                "Invalid application context: needs to be of type [" + requiredContextClass().getName() + "]");
        }
        // 1.赋值子容器
        this.applicationContext = context;
        // 2.初始化messageSourceAccessor
        this.messageSourceAccessor = new MessageSourceAccessor(context);
        // 3.这里的initApplicationContext(context)由子类WebApplicationObjectSupport复写
        initApplicationContext(context);
    }
    else {
        // Ignore reinitialization if same context passed in.
        if (this.applicationContext != context) {
            throw new ApplicationContextException(
                "Cannot reinitialize with different application context: current one is [" +
                this.applicationContext + "], passed-in one is [" + context + "]");
        }
    }
}
4.2.1.3 WebApplicationObjectSupport#initApplicationContext(ApplicationContext context)
/**
 * Calls {@link #initServletContext(javax.servlet.ServletContext)} if the
 * given ApplicationContext is a {@link WebApplicationContext}.
 */
@Override
protected void initApplicationContext(ApplicationContext context) {
    // 1.这里会先调用父类的方法, 即ApplicationObjectSupport的initApplicationContext(ApplicationContext context), 最终会回调到
    // SimpleUrlHandlerMapping#initApplicationContext()
    super.initApplicationContext(context);
    if (this.servletContext == null && context instanceof WebApplicationContext) {
        this.servletContext = ((WebApplicationContext) context).getServletContext();
        if (this.servletContext != null) {
            initServletContext(this.servletContext);
        }
    }
}
4.2.1.4 SimpleUrlHandlerMapping#initApplicationContext()
@Override
public void initApplicationContext() throws BeansException {
    // 先调用父类的initApplicationContext(), 这里调用的是 AbstractHandlerMapping#initApplicationContext()
    super.initApplicationContext();
    // 这里的urlMap存的是url和处理器的关联关系, 初始化时已经有了1个
    // ("/**", DefaultServletHttpRequestHandler字符串)
    registerHandlers(this.urlMap);
}
4.2.1.5 SimpleUrlHandlerMapping#registerHandlers(Map<String, Object> urlMap)
/**
 * Register all handlers specified in the URL map for the corresponding paths.
 * @param urlMap Map with URL paths as keys and handler beans or bean names as values
 * @throws BeansException if a handler couldn't be registered
 * @throws IllegalStateException if there is a conflicting handler registered
 */
protected void registerHandlers(Map<String, Object> urlMap) throws BeansException {
    if (urlMap.isEmpty()) {
        logger.warn("Neither 'urlMap' nor 'mappings' set on SimpleUrlHandlerMapping");
    }
    else {
        // 1.urlMap不为空, ("/**", DefaultServletHttpRequestHandler)
        for (Map.Entry<String, Object> entry : urlMap.entrySet()) {
            String url = entry.getKey();
            Object handler = entry.getValue();
            // Prepend with slash if not already present.
            if (!url.startsWith("/")) {
                url = "/" + url;
            }
            // Remove whitespace from handler bean name.
            if (handler instanceof String) {
                handler = ((String) handler).trim();
            }
            // 2.注册handler, 向父类AbstractUrlHandlerMapping中注册, urlMap
            // handlerMap成员变量添加("/**", DefaultServletHttpRequestHandler)
            registerHandler(url, handler);
        }
    }
}

4.2.2 BeanNameUrlHandlerMapping

4.2.2.1 结构图

根据[@Spring源码,在bean的创建和初始化过程中,会先后八次调用BeanPostProcessor,在属性注入之后,会第七次调用BeanPostProcessor,执行部分Aware回调接口,这里会回调其父类ApplicationObjectSupport的setApplicationContext(ApplicationContext](/Spring源码,在bean的创建和初始化过程中,会先后八次调用BeanPostProcessor,在属性注入之后,会第七次调用BeanPostProcessor,执行部分Aware回调接口,这里会回调其父类ApplicationObjectSupport的setApplicationContext(ApplicationContext) context)方法

4.3.2.2 ApplicationObjectSupport#setApplicationContext(ApplicationContext context)
@Override
public final void setApplicationContext(ApplicationContext context) throws BeansException {
    if (context == null && !isContextRequired()) {
        // Reset internal context state.
        this.applicationContext = null;
        this.messageSourceAccessor = null;
    }
    else if (this.applicationContext == null) {
        // Initialize with passed-in context.
        if (!requiredContextClass().isInstance(context)) {
            throw new ApplicationContextException(
                "Invalid application context: needs to be of type [" + requiredContextClass().getName() + "]");
        }
        // 1.赋值子容器
        this.applicationContext = context;
        // 2.初始化messageSourceAccessor
        this.messageSourceAccessor = new MessageSourceAccessor(context);
        // 3.这里的initApplicationContext(context)由子类WebApplicationObjectSupport复写
        initApplicationContext(context);
    }
    else {
        // Ignore reinitialization if same context passed in.
        if (this.applicationContext != context) {
            throw new ApplicationContextException(
                "Cannot reinitialize with different application context: current one is [" +
                this.applicationContext + "], passed-in one is [" + context + "]");
        }
    }
}
4.2.2.3 WebApplicationObjectSupport#initApplicationContext(ApplicationContext context)
/**
 * Calls {@link #initServletContext(javax.servlet.ServletContext)} if the
 * given ApplicationContext is a {@link WebApplicationContext}.
 */
@Override
protected void initApplicationContext(ApplicationContext context) {
    // 1.这里会先调用父类的方法, 即ApplicationObjectSupport的initApplicationContext(ApplicationContext context), 最终会回调到
    // AbstractDelectingUrlHandlerMapping#initApplicationContext()
    super.initApplicationContext(context);
    if (this.servletContext == null && context instanceof WebApplicationContext) {
        this.servletContext = ((WebApplicationContext) context).getServletContext();
        if (this.servletContext != null) {
            initServletContext(this.servletContext);
        }
    }
}
4.2.2.4 AbstractDelectingUrlHandlerMapping#initApplicationContext()
/**
 * Calls the {@link #detectHandlers()} method in addition to the
 * superclass's initialization.
 */
@Override
public void initApplicationContext() throws ApplicationContextException {
    // 1.调用父类 AbstractHandlerMapping#initApplicationContext()
    super.initApplicationContext();
    // 2.调用
    detectHandlers();
}
4.2.2.5 AbstractDelectingUrlHandlerMapping#detectHandlers()
/**
 * Register all handlers found in the current ApplicationContext.
 * <p>The actual URL determination for a handler is up to the concrete
 * {@link #determineUrlsForHandler(String)} implementation. A bean for
 * which no such URLs could be determined is simply not considered a handler.
 * @throws org.springframework.beans.BeansException if the handler couldn't be registered
 * @see #determineUrlsForHandler(String)
 */
protected void detectHandlers() throws BeansException {
    if (logger.isDebugEnabled()) {
        logger.debug("Looking for URL mappings in application context: " + getApplicationContext());
    }
    String[] beanNames = (this.detectHandlersInAncestorContexts ?
                          BeanFactoryUtils.beanNamesForTypeIncludingAncestors(getApplicationContext(), Object.class) :
                          getApplicationContext().getBeanNamesForType(Object.class));

    // Take any bean name that we can determine URLs for.
    for (String beanName : beanNames) {
        // 目前determineUrlsForHandler(beanName)都返回空
        String[] urls = determineUrlsForHandler(beanName);
        if (!ObjectUtils.isEmpty(urls)) {
            // URL paths found: Let's consider it a handler.
            registerHandler(urls, beanName);
        }
        else {
            if (logger.isDebugEnabled()) {
                logger.debug("Rejected bean name '" + beanName + "': no URL paths identified");
            }
        }
    }
}

4.2.3 RequestMappingHandlerMapping(重点)

4.2.3.1 结构图

根据[@Spring源码,在bean的创建和初始化过程中,会先后八次调用BeanPostProcessor,在属性注入之后,会第七次调用BeanPostProcessor,执行部分Aware回调接口,这里会回调其父类ApplicationObjectSupport的setApplicationContext(ApplicationContext](/Spring源码,在bean的创建和初始化过程中,会先后八次调用BeanPostProcessor,在属性注入之后,会第七次调用BeanPostProcessor,执行部分Aware回调接口,这里会回调其父类ApplicationObjectSupport的setApplicationContext(ApplicationContext) context)方法

4.3 处理请求

4.3.1 预备

1.当一个请求过来时,优先使用Filter处理,处理完之后根据配置找到对应的Servlet,我们这里只配置了一个DispatcherServlet用于处理所有请求
2.Dispatcher处理请求时,优先调用service(req, resp)方法,该方法由其父类FrameworkServlet实现

4.3.2 FrameworkServlet#service(HttpServletRequest request, HttpServletResponse response)

/**
 * Override the parent class implementation in order to intercept PATCH requests.
 */
@Override
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    HttpMethod httpMethod = HttpMethod.resolve(request.getMethod());
    if (HttpMethod.PATCH == httpMethod || httpMethod == null) {
        processRequest(request, response);
    }
    else {
        // 调用父类的service(req,resp)方法, 见@4.3.3
        super.service(request, response);
    }
}

4.3.3 HttpServlet#service(HttpServletRequest req, HttpServletResponse resp)

这个方法根据不同的请求方法调用不同的处理方法,如doGet(),doPost()等,具体的方法有子类FrameworkServlet实现

protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    String method = req.getMethod();

    if (method.equals(METHOD_GET)) {
        long lastModified = getLastModified(req);
        if (lastModified == -1) {
            // servlet doesn't support if-modified-since, no reason
            // to go through further expensive logic
            doGet(req, resp);
        } else {
            long ifModifiedSince = req.getDateHeader(HEADER_IFMODSINCE);
            if (ifModifiedSince < (lastModified / 1000 * 1000)) {
                // If the servlet mod time is later, call doGet()
                // Round down to the nearest second for a proper compare
                // A ifModifiedSince of -1 will always be less
                maybeSetLastModified(resp, lastModified);
                doGet(req, resp);
            } else {
                resp.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
            }
        }

    } else if (method.equals(METHOD_HEAD)) {
        long lastModified = getLastModified(req);
        maybeSetLastModified(resp, lastModified);
        doHead(req, resp);

    } else if (method.equals(METHOD_POST)) {
        doPost(req, resp);

    } else if (method.equals(METHOD_PUT)) {
        doPut(req, resp);	

    } else if (method.equals(METHOD_DELETE)) {
        doDelete(req, resp);

    } else if (method.equals(METHOD_OPTIONS)) {
        doOptions(req,resp);

    } else if (method.equals(METHOD_TRACE)) {
        doTrace(req,resp);

    } else {
        //
        // Note that this means NO servlet supports whatever
        // method was requested, anywhere on this server.
        //

        String errMsg = lStrings.getString("http.method_not_implemented");
        Object[] errArgs = new Object[1];
        errArgs[0] = method;
        errMsg = MessageFormat.format(errMsg, errArgs);

        resp.sendError(HttpServletResponse.SC_NOT_IMPLEMENTED, errMsg);
    }
}

4.3.4 Framework#doGet(HttpServletRequest request, HttpServletResponse response)

@Override
protected final void doGet(HttpServletRequest request, HttpServletResponse response)
    throws ServletException, IOException {
    // 见@4.3.5
    processRequest(request, response);
}

4.3.5 Framework#processRequest(HttpServletRequest request, HttpServletResponse response)

/**
	 * Process this request, publishing an event regardless of the outcome.
	 * <p>The actual event handling is performed by the abstract
	 * {@link #doService} template method.
	 */
protected final void processRequest(HttpServletRequest request, HttpServletResponse response)
    throws ServletException, IOException {

    long startTime = System.currentTimeMillis();
    Throwable failureCause = null;

    LocaleContext previousLocaleContext = LocaleContextHolder.getLocaleContext();
    // 1.构建localeContext
    LocaleContext localeContext = buildLocaleContext(request);

    RequestAttributes previousAttributes = RequestContextHolder.getRequestAttributes();
    // 2.构建ServletRequestAttributes
    ServletRequestAttributes requestAttributes = buildRequestAttributes(request, response, previousAttributes);

    WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
    asyncManager.registerCallableInterceptor(FrameworkServlet.class.getName(), new RequestBindingInterceptor());
	// 3.初始化LocaleContextHolder, 主要是一些线程共享变量 ThreadLocal
    initContextHolders(request, localeContext, requestAttributes);

    try {
        // 4.调用doService(req, resp), 由子类DispatcherServlet实现,见@4.3.6
        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 {
        // 5.销毁LocaleContextHolder, 主要是一些线程共享变量 ThreadLocal
        resetContextHolders(request, previousLocaleContext, previousAttributes);
        if (requestAttributes != null) {
            requestAttributes.requestCompleted();
        }

        if (logger.isDebugEnabled()) {
            if (failureCause != null) {
                this.logger.debug("Could not complete request", failureCause);
            }
            else {
                if (asyncManager.isConcurrentHandlingStarted()) {
                    logger.debug("Leaving response open for concurrent processing");
                }
                else {
                    this.logger.debug("Successfully completed request");
                }
            }
        }
		// 6.发布处理请求事件
        publishRequestHandledEvent(request, response, startTime, failureCause);
    }
}

4.3.6 DispatcherServlet#doService(HttpServletRequest request, HttpServletResponse response)

@Override
protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {
    if (logger.isDebugEnabled()) {
        String resumed = WebAsyncUtils.getAsyncManager(request).hasConcurrentResult() ? " resumed" : "";
        logger.debug("DispatcherServlet with name '" + getServletName() + "'" + resumed +
                     " processing " + request.getMethod() + " request for [" + getRequestUri(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<String, Object>();
        Enumeration<?> attrNames = request.getAttributeNames();
        while (attrNames.hasMoreElements()) {
            String attrName = (String) attrNames.nextElement();
            if (this.cleanupAfterInclude || attrName.startsWith("org.springframework.web.servlet")) {
                attributesSnapshot.put(attrName, request.getAttribute(attrName));
            }
        }
    }

    // Make framework objects available to handlers and view objects.
    // 1.将框架中的一些对象暴露给其他处理器, 比如localeResolver
    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 {
        // 2.核心方法, 作请求分发处理, 见@4.3.7
        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);
            }
        }
    }
}

4.3.7 DispatcherServlet#doDispatch(HttpServletRequest request, HttpServletResponse response)

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 {
            // 1.判断是否是文件上传
            processedRequest = checkMultipart(request);
            multipartRequestParsed = (processedRequest != request);

            // Determine handler for the current request.
            // 2.根据请求获取HandlerExecutionChain, 见@4.3.8
            // 这里由RequestMappingHandlerMapping根据请求url匹配到对应的Controller的对应方法, 封装成HandlerExecutionChain
        	// 这个chain封装了一个HandlerMethod(url对应的Controller和对应的method)以及一个拦截器: ConversionServiceExpodingInterceptor
            mappedHandler = getHandler(processedRequest);
            // 3.没找到直接返回404
            if (mappedHandler == null || mappedHandler.getHandler() == null) {
                noHandlerFound(processedRequest, response);
                return;
            }

            // Determine handler adapter for the current request.
            // 4.根据handlerMethod找到HandlerAdapter, 这里获取的是RequestMappingHandlerAdapter
            HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());

            // Process last-modified header, if supported by the handler.
            String method = request.getMethod();
            boolean isGet = "GET".equals(method);
            if (isGet || "HEAD".equals(method)) {
                long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
                if (logger.isDebugEnabled()) {
                    logger.debug("Last-Modified value for [" + getRequestUri(request) + "] is: " + lastModified);
                }
                if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
                    return;
                }
            }
		   // 5.前面: mappedHandler是HandlerExecutionChain, 是对对应处理器HandlerMethod以及拦截器的封装,
            // 这里会先调用拦截器的preHandle方法进行拦截
            if (!mappedHandler.applyPreHandle(processedRequest, response)) {
                return;
            }

            // Actually invoke the handler.
            // 6.调用处理器方法, 见@4.3.10
            mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

            if (asyncManager.isConcurrentHandlingStarted()) {
                return;
            }
		   // 7.mv == null, 直接跳过
            applyDefaultViewName(processedRequest, mv);
            // 8.调用拦截器的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);
        }
        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);
            }
        }
    }
}

4.3.8 DispatcherServlet#getHandler(HttpServletRequest request)

/**
	 * Return the HandlerExecutionChain for this request.
	 * <p>Tries all handler mappings in order.
	 * @param request current HTTP request
	 * @return the HandlerExecutionChain, or {@code null} if no handler could be found
	 */
protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
    // 这里的handlerMappings有三个, 且已经排序了, 第一个是RequestMappingHandlerMapping
    for (HandlerMapping hm : this.handlerMappings) {
        if (logger.isTraceEnabled()) {
            logger.trace(
                "Testing handler map [" + hm + "] in DispatcherServlet with name '" + getServletName() + "'");
        }
        // 这里由RequestMappingHandlerMapping根据请求url匹配到对应的HandlerMethod, 封装成HandlerExecutionChain
        // 这个chain封装了对应的HandlerMethod以及一个拦截器: ConversionServiceExpodingInterceptor
        HandlerExecutionChain handler = hm.getHandler(request);
        if (handler != null) {
            return handler;
        }
    }
    return null;
}

4.3.9 DispatcherServlet#getHandlerAdapter(Object handler)

/**
 * Return the HandlerAdapter for this handler object.
 * @param handler the handler object to find an adapter for
 * @throws ServletException if no HandlerAdapter can be found for the handler. This is a fatal error.
 */
protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
    // 这里的handlerAdapters有三个: HttpRequestHandlerAdapter、SimpleControllerHandlerAdapter、RequestMappingHandlerAdapter
    for (HandlerAdapter ha : this.handlerAdapters) {
        if (logger.isTraceEnabled()) {
            logger.trace("Testing handler adapter [" + ha + "]");
        }
        // 因为前期用的RequestMappingHandlerMapping, 所以这里获取到的是 RequestMappingHandlerAdapter
        if (ha.supports(handler)) {
            return ha;
        }
    }
    throw new ServletException("No adapter for handler [" + handler +
                               "]: The DispatcherServlet configuration needs to include a HandlerAdapter that supports this handler");
}

4.3.10 AbstractHandlerMethodAdapter#handle(HttpServletRequest request, HttpServletResponse response, Object handler)

public final ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
    throws Exception {
	// 这里由子类 RequstMappingHandlerAdapter 实现, 见@4.3.11 
    return handleInternal(request, response, (HandlerMethod) handler);
}

4.3.11 RequstMappingHandlerAdapter#handleInternal(HttpServletRequest request, HttpServletResponse response, HandlerMethod handlerMethod)

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

    ModelAndView mav;
    // 1.校验请求方法和是否需要session
    checkRequest(request);

    // Execute invokeHandlerMethod in synchronized block if required.
    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...
        // 2.进入, 返回ModelAndView, 这里使用的rest方法, 不会返回ModelAndView
        mav = invokeHandlerMethod(request, response, handlerMethod);
    }

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

    return mav;
}

5.springmvc组件解析

5.1 入口

1.由前面分析, servlet容器在加载web.xml时, 会初始化DispatcherServlet, 此时会执行DispatcherServlet的静态代码块

static {
    try {
        // DEFAULT_STRATEGIES_PATH == DispatcherServlet.properties
        // 即加载DispatcherServlet类时会加载 DispatcherServlet.properties 配置文件, 存储在 defaultStrategies
        // 查看 DispatcherServlet.properties, 可以看到, 是DispatcherServlet中九大组件的默认实现类, 其中有八个组件的默认实现类, 缺少一个MultipartResolver, 因此, 如果没有在 springmvc-config.xml文件中配置, 则不会有 MultipartResolver, 此时无法解析文件上传等功能
        ClassPathResource resource = new ClassPathResource(DEFAULT_STRATEGIES_PATH, DispatcherServlet.class);
        defaultStrategies = PropertiesLoaderUtils.loadProperties(resource);
    }
    catch (IOException ex) {
        throw new IllegalStateException("Could not load '" + DEFAULT_STRATEGIES_PATH + "': " + ex.getMessage());
    }
}

DispatcherServlet.properties

org.springframework.web.servlet.LocaleResolver=org.springframework.web.servlet.i18n.AcceptHeaderLocaleResolver
org.springframework.web.servlet.ThemeResolver=org.springframework.web.servlet.theme.FixedThemeResolver
org.springframework.web.servlet.HandlerMapping=org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping,\
	org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping
org.springframework.web.servlet.HandlerAdapter=org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter,\
	org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter,\
	org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter
org.springframework.web.servlet.HandlerExceptionResolver=org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver,\
	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
org.springframework.web.servlet.FlashMapManager=org.springframework.web.servlet.support.SessionFlashMapManager

2.子容器XmlWebApplicationContext启动时,发布ContextRefreshedEvent事件,被已经添加的ContextRefreshListener监听,回调其onApplicationEvent(ContextRefreshedEvent event)方法,这个方法中调用了DispatcherServlet的onRefresh(ApplicationContext context)方法,在onRefresh方法中会调用核心方法 initStrategies,在 initStrategies 方法中完成九大组件的初始化

3.注意:以上配置文件中的组件不会一开始就加载到子容器XmlWebApplicationContext中,子容器一开始只会加载其他核心bean以及配置文件springmvc中bean,所以如果我们在springmvc.xml文件中配置了相关组件,优先会使用我们配置的,如果没有,才会使用 DispatcherServlet.properties 配置的相关组件

DispatcherServlet#onRefresh(ApplicationContext context)

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

DispatcherServlet#initStrategies(ApplicationContext context)

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

5.2 MultipartResolver

MultipartResolver是九大组件之一,用于处理文件上传

5.2.1 初始化

private void initMultipartResolver(ApplicationContext context) {
    try {
        // 1.直接从子spring容器中获取, 如果springmvc-config.xml文件中没有配置, 则获取失败
        this.multipartResolver = context.getBean(MULTIPART_RESOLVER_BEAN_NAME, MultipartResolver.class);
        if (logger.isTraceEnabled()) {
            logger.trace("Detected " + this.multipartResolver);
        }
        else if (logger.isDebugEnabled()) {
            logger.debug("Detected " + this.multipartResolver.getClass().getSimpleName());
        }
    }
    catch (NoSuchBeanDefinitionException ex) {
        // Default is no multipart resolver.
        // 2.获取失败后, 也不会从 DispatcherServlet.properties 配置中读取, 因为 DispatcherServlet.properties 配置文件中也没有配置当前组件
        this.multipartResolver = null;
        if (logger.isTraceEnabled()) {
            logger.trace("No MultipartResolver '" + MULTIPART_RESOLVER_BEAN_NAME + "' declared");
        }
    }
}

5.2.2 实现

MultipartResolver有两个实现:CommonsMultipartResolver 和 StandardServletMultipartResolver,如果在springmvc中需要使用,则需要在springmvc-config.xml文件中进行注册,否则默认无法解析文件上传

5.2.2.1 CommonsMultipartResolver

1.在springmvc.config文件中配置CommonsMultipartResolver

<bean class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
    <property name="maxUploadSize" value="104857600" />
    <property name="maxInMemorySize" value="104857600" />
</bean>

2.pom.xml文件中需要引入commons-file,因为CommonsMultipartResolver借助了commons-file

<dependency>
    <groupId>commons-fileupload</groupId>
    <artifactId>commons-fileupload</artifactId>
    <version>1.3.1</version>
</dependency>
5.2.2.2 StandardServletMultipartResolver

这个是springboot中默认引入的bean,springboot采用spi机制,在spring-boot-autoconfigure包的resources/META-INF/spring.factories文件中,引入了MultipartAutoConfiguration,在MultipartAutoConfiguration中根据条件,向spring容器中注册了 StandardServletMultipartResolver

5.2.3 应用

在核心处理流程中,DispatcherServlet#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 {
            // 1.判断是否是文件上传, 判断条件: Content-Type 是否以 multipart/ 开头
            // 并将 HttpServletRequest 封装成 MultipartHttpServletRequest, 具体实现暂略
            processedRequest = checkMultipart(request);
            multipartRequestParsed = (processedRequest != request);

            ......
}

5.3 HandlerMapping

HandlerMapping是九大组件之一,负责为请求找到合适的 HandlerExecutionChain 处理器执行链,包含处理器(handler)和拦截器(interceptors),处理器通常就是我们在@Controller下@RequestMapping注解对应的方法的封装,拦截器是对处理请求进行增强处理,用于对处理器的增强

5.3.1 初始化

private void initHandlerMappings(ApplicationContext context) {
    this.handlerMappings = null;
	// 1.如果开启探测功能, 则会从springmvc容器中扫描所有的 HandlerMapping, 添加到 handlerMappings 中, 默认开启, 默认找到3个
    // 默认3个是何时添加到springmvc容器中?是在初始化子springmvc容器的过程中, 解析springmvc-config.xml配置文件的过程中创建的BeanDefinition, 这个后期有空再具体写文档
    // SimpleUrlHandlerMapping、BeanNameUrlHandlerMapping、RequestMappingHandlerMapping, 下面会进行重新排序
    if (this.detectAllHandlerMappings) {
        // Find all HandlerMappings in the ApplicationContext, including ancestor contexts.
        Map<String, HandlerMapping> matchingBeans =
            BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerMapping.class, true, false);
        if (!matchingBeans.isEmpty()) {
            this.handlerMappings = new ArrayList<>(matchingBeans.values());
            // We keep HandlerMappings in sorted order.
            // 重新排序: RequestMappingHandlerMapping、BeanNameUrlHandlerMapping、SimpleUrlHandlerMapping
            AnnotationAwareOrderComparator.sort(this.handlerMappings);
        }
    }
    // 2.关闭探测功能时, 获得Bean名称为 handlerMapping 对应的 Bean, 将其添加至 handlerMappings
    else {
        try {
            HandlerMapping hm = context.getBean(HANDLER_MAPPING_BEAN_NAME, HandlerMapping.class);
            this.handlerMappings = Collections.singletonList(hm);
        }
        catch (NoSuchBeanDefinitionException ex) {
            // Ignore, we'll add a default HandlerMapping later.
        }
    }

    // Ensure we have at least one HandlerMapping, by registering
    // a default HandlerMapping if no other mappings are found.
    // 3.如果未获得到, 则获得默认配置 DispatcherServlet.properties 中的 HandlerMapping 类
    if (this.handlerMappings == null) {
        this.handlerMappings = getDefaultStrategies(context, HandlerMapping.class);
        if (logger.isTraceEnabled()) {
            logger.trace("No HandlerMappings declared for servlet '" + getServletName() +
                         "': using default strategies from DispatcherServlet.properties");
        }
    }
}

5.3.2 实现

5.3.2.1 结构图

1.蓝色框 AbstractHandlerMapping 抽象类, 实现了getHandler方法, 用于处理器映射器找到对应的 HandlerExecutionChain, getHandler中采用模板方法模式, 子类需要实现 getHandlerInternal(HttpServletRequest request) 抽象方法
2.AbstractHandlerMapping的子类主要分为两类:
黄色框 AbstractUrlHandlerMapping, 是基于url进行匹配的, 目前这种方式已经基本不用了, 我们初始化获取的 SimpleUrlHandlerMapping 和 BeanNameUrlHandlerMapping 就是属于此类, 所以接下来也不会分析了
红色框 AbstractHandlerMethodMapping系, 基于Method匹配, 我们现在使用的@RequestMapping注解就是基于这种方式, 这个是我们接下来会具体分析的
5.3.2.2 AbstractHandlerMapping
public abstract class AbstractHandlerMapping extends WebApplicationObjectSupport implements HandlerMapping, Ordered, BeanNameAware {

	/**
	 * 默认处理器
	 */
	@Nullable
	private Object defaultHandler;

	/**
	 * URL 路径工具类
	 */
	private UrlPathHelper urlPathHelper = new UrlPathHelper();

	/**
	 * 路径匹配器
	 */
	private PathMatcher pathMatcher = new AntPathMatcher();

	/**
	 * 配置的拦截器数组.
	 *
	 * 在 {@link #initInterceptors()} 方法中,初始化到 {@link #adaptedInterceptors} 中
	 *
	 * 添加方式有两种:
	 * 1. {@link #setInterceptors(Object...)} 方法
	 * 2. {@link #extendInterceptors(List)} 方法
	 */
	private final List<Object> interceptors = new ArrayList<>();

	/**
	 * 初始化后的拦截器 HandlerInterceptor 数组
	 */
	private final List<HandlerInterceptor> adaptedInterceptors = new ArrayList<>();

	......
}

initApplicationContext

@Override
protected void initApplicationContext() throws BeansException {
    // 1.空实现,交给子类实现, 用于注册自定义的拦截器到 interceptors 中, 目前暂无子类实现
    extendInterceptors(this.interceptors);
    // 2.扫描已注册的 MappedInterceptor 的 Bean,添加到 mappedInterceptors 中
    detectMappedInterceptors(this.adaptedInterceptors);
    // 3.将 interceptors 初始化成 HandlerInterceptor 类型,添加到 mappedInterceptors 中
    initInterceptors();
}

getHandler

@Override
@Nullable
public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
    // 1.获得处理器(HandlerMethod 或者 HandlerExecutionChain), 该方法是抽象方法, 由子类实现
    Object handler = getHandlerInternal(request);
    // 2.获得不到, 则使用默认处理器
    if (handler == null) {
        handler = getDefaultHandler();
    }
    // 3.还是获得不到, 则返回 null
    if (handler == null) {
        return null;
    }
    // Bean name or resolved handler?
    // 4.如果找到的处理器是 String 类型, 则从 Spring 容器中找到对应的 Bean 作为处理器
    if (handler instanceof String) {
        String handlerName = (String) handler;
        handler = obtainApplicationContext().getBean(handlerName);
    }

    // 5.创建 HandlerExecutionChain 对象(包含处理器和拦截器), 见下
    HandlerExecutionChain executionChain = getHandlerExecutionChain(handler, request);

    if (logger.isTraceEnabled()) {
        logger.trace("Mapped to " + handler);
    }
    else if (logger.isDebugEnabled() && !request.getDispatcherType().equals(DispatcherType.ASYNC)) {
        logger.debug("Mapped to " + executionChain.getHandler());
    }

    if (CorsUtils.isCorsRequest(request)) {
        CorsConfiguration globalConfig = this.corsConfigurationSource.getCorsConfiguration(request);
        CorsConfiguration handlerConfig = getCorsConfiguration(handler, request);
        CorsConfiguration config = (globalConfig != null ? globalConfig.combine(handlerConfig) : handlerConfig);
        executionChain = getCorsHandlerExecutionChain(request, executionChain, config);
    }

    return executionChain;
}

getHandlerExecutionChain

protected HandlerExecutionChain getHandlerExecutionChain(Object handler, HttpServletRequest request) {
    // 1.创建 HandlerExecutionChain 对象
    HandlerExecutionChain chain = (handler instanceof HandlerExecutionChain ? (HandlerExecutionChain) handler
            : new HandlerExecutionChain(handler));

    // 2.获得请求路径
    String lookupPath = this.urlPathHelper.getLookupPathForRequest(request);
    // 3.遍历 adaptedInterceptors 数组, 获得请求匹配的拦截器
    for (HandlerInterceptor interceptor : this.adaptedInterceptors) {
        //4.需要匹配,若路径匹配,则添加到 chain 中
        if (interceptor instanceof MappedInterceptor) {
            MappedInterceptor mappedInterceptor = (MappedInterceptor) interceptor;
            if (mappedInterceptor.matches(lookupPath, this.pathMatcher)) { // 匹配
                chain.addInterceptor(mappedInterceptor.getInterceptor());
            }
        }
        // 5.无需匹配,直接添加到 chain 中
        else {
            chain.addInterceptor(interceptor);
        }
    }
    return chain
}
5.3.2.3 RequestMappingHandlerMapping

结构图

由结构图可以看出,RequestMappingHandlerMapping间接继承了父类ApplicationObjectSupport,实现了Aware接口,根据[@Spring源码,在bean的创建和初始化过程中,会先后八次调用BeanPostProcessor,在属性注入之后,会第七次调用BeanPostProcessor,执行部分Aware回调接口,这里会回调其父类ApplicationObjectSupport的setApplicationContext(ApplicationContext](/Spring源码,在bean的创建和初始化过程中,会先后八次调用BeanPostProcessor,在属性注入之后,会第七次调用BeanPostProcessor,执行部分Aware回调接口,这里会回调其父类ApplicationObjectSupport的setApplicationContext(ApplicationContext) context)方法

ApplicationObjectSupport#setApplicationContext(ApplicationContext context)

@Override
public final void setApplicationContext(ApplicationContext context) throws BeansException {
    if (context == null && !isContextRequired()) {
        // Reset internal context state.
        this.applicationContext = null;
        this.messageSourceAccessor = null;
    }
    else if (this.applicationContext == null) {
        // Initialize with passed-in context.
        if (!requiredContextClass().isInstance(context)) {
            throw new ApplicationContextException(
                "Invalid application context: needs to be of type [" + requiredContextClass().getName() + "]");
        }
        // 1.赋值子容器
        this.applicationContext = context;
        // 2.初始化messageSourceAccessor
        this.messageSourceAccessor = new MessageSourceAccessor(context);
        // 3.这里的initApplicationContext(context)由子类WebApplicationObjectSupport复写
        initApplicationContext(context);
    }
    else {
        // Ignore reinitialization if same context passed in.
        if (this.applicationContext != context) {
            throw new ApplicationContextException(
                "Cannot reinitialize with different application context: current one is [" +
                this.applicationContext + "], passed-in one is [" + context + "]");
        }
    }
}

WebApplicationObjectSupport#initApplicationContext(ApplicationContext context)

/**
 * Calls {@link #initServletContext(javax.servlet.ServletContext)} if the
 * given ApplicationContext is a {@link WebApplicationContext}.
 */
@Override
protected void initApplicationContext(ApplicationContext context) {
    // 1.这里会先调用父类的方法, 即ApplicationObjectSupport的initApplicationContext(ApplicationContext context), 最终会回调到
    // AbstractHandlerMapping#initApplicationContext()
    super.initApplicationContext(context);
    if (this.servletContext == null && context instanceof WebApplicationContext) {
        this.servletContext = ((WebApplicationContext) context).getServletContext();
        if (this.servletContext != null) {
            initServletContext(this.servletContext);
        }
    }
}

AbstractHandlerMapping#initApplicationContext()

/**
 * Initializes the interceptors.
 * @see #extendInterceptors(java.util.List)
 * @see #initInterceptors()
 */
@Override
protected void initApplicationContext() throws BeansException {
    extendInterceptors(this.interceptors);
    detectMappedInterceptors(this.adaptedInterceptors);
    initInterceptors();
}

在第七次BeanPostProcessor调用后,会调用bean的初始化方法,因为RequestMappingHandlerMapping实现了InitializingBean接口,所以会回调其afterPropertiesSet()方法,在这里真正完成url和HandlerMethod的绑定

RequestMappingHandlerMapping#afterPropertiesSet()

@Override
public void afterPropertiesSet() {
    this.config = new RequestMappingInfo.BuilderConfiguration();
    this.config.setUrlPathHelper(getUrlPathHelper());
    this.config.setPathMatcher(getPathMatcher());
    this.config.setSuffixPatternMatch(this.useSuffixPatternMatch);
    this.config.setTrailingSlashMatch(this.useTrailingSlashMatch);
    this.config.setRegisteredSuffixPatternMatch(this.useRegisteredSuffixPatternMatch);
    this.config.setContentNegotiationManager(getContentNegotiationManager());
	// 调用父类 afterPropertiesSet(), 由AbstractHandlerMethodMapping实现
    super.afterPropertiesSet();
}

AbstractHandlerMethodMapping#afterPropertiesSet()

@Override
public void afterPropertiesSet() {
    initHandlerMethods();
}

AbstractHandlerMethodMapping#initHandlerMethods()

/**
 * Scan beans in the ApplicationContext, detect and register handler methods.
 * @see #getCandidateBeanNames()
 * @see #processCandidateBean
 * @see #handlerMethodsInitialized
 */
protected void initHandlerMethods() {
    for (String beanName : getCandidateBeanNames()) {
        // 不以 scopedTarget. 开头, 则进入
        if (!beanName.startsWith(SCOPED_TARGET_NAME_PREFIX)) {
            processCandidateBean(beanName);
        }
    }
    handlerMethodsInitialized(getHandlerMethods());
}

AbstractHandlerMethodMapping#processCandidateBean(String beanName)

protected void processCandidateBean(String beanName) {
    Class<?> beanType = null;
    try {
        // 1.获取Class对象
        beanType = obtainApplicationContext().getType(beanName);
    }
    catch (Throwable ex) {
        // An unresolvable bean type, probably from a lazy bean - let's ignore it.
        if (logger.isTraceEnabled()) {
            logger.trace("Could not resolve type for bean '" + beanName + "'", ex);
        }
    }
    // 2.判断Class是否有@RequestMapping注解或者@Controller注解
    if (beanType != null && isHandler(beanType)) {
        // 3.封装 HandlerMethod, 存储到mappingLookup中
        // key = @RequestMapping中的url
        // value = HandlerMethod
        // 在这里绑定了url和对应Controller的处理方法的封装 HandlerMethod, 存储到了其父类AbstractHandlerMehodMapping的属性mappingRegistry中, 见下
        detectHandlerMethods(beanName);
    }
}

AbstractHandlerMethodMapping#detectHandlerMethods

protected void detectHandlerMethods(Object handler) {
    Class<?> handlerType = (handler instanceof String ?
                            obtainApplicationContext().getType((String) handler) : handler.getClass());

    if (handlerType != null) {
        Class<?> userType = ClassUtils.getUserClass(handlerType);
        Map<Method, T> methods = MethodIntrospector.selectMethods(userType,
            (MethodIntrospector.MetadataLookup<T>) method -> {
                try {
                   return getMappingForMethod(method, userType);
               }
               catch (Throwable ex) {
                   throw new IllegalStateException("Invalid mapping on handler class [" +  userType.getName() + "]: " + method, ex);
               }
        });
        if (logger.isTraceEnabled()) {
            logger.trace("Mapped " + methods.size() + " handler method(s) for " + userType + ": " + methods);
        }
        methods.forEach((method, mapping) -> {
            Method invocableMethod = AopUtils.selectInvocableMethod(method, userType);
            // 注册url和对应的Method, 见下
            registerHandlerMethod(handler, invocableMethod, mapping);
        });
    }
}

AbstractHandlerMethodMapping#registerHandlerMethod

protected void registerHandlerMethod(Object handler, Method method, T mapping) {
    // 核心方法
    this.mappingRegistry.register(mapping, handler, method);
}

MappingRegistry#register

public void register(T mapping, Object handler, Method method) {
    // 1.获取写锁
    this.readWriteLock.writeLock().lock();
    try {
        // 2.创建 Method 对应的 HandlerMethod
        HandlerMethod handlerMethod = createHandlerMethod(handler, method);
        assertUniqueMethodMapping(handlerMethod, mapping);
        // 3.存储 (mapping, HandlerMethod) 关联关系到 mappingLookup属性
        this.mappingLookup.put(mapping, handlerMethod);
	   // 4.获得 mapping 对应的普通 URL 数组
        List<String> directUrls = getDirectUrls(mapping);
        for (String url : directUrls) {
            // 5.将 url 和 mapping 的映射关系保存至 urlLookup属性
            this.urlLookup.add(url, mapping);
        }

        String name = null;
        // 6.初始化 nameLookup
        if (getNamingStrategy() != null) {
            // 7.获得 Mapping 的名字
            name = getNamingStrategy().getName(handlerMethod, mapping);
            // 8.将 mapping 的名字与 HandlerMethod 的映射关系保存至 nameLookup
            addMappingName(name, handlerMethod);
        }
	    // 9.初始化 CorsConfiguration 配置对象
        CorsConfiguration corsConfig = initCorsConfiguration(handler, method, mapping);
        if (corsConfig != null) {
            this.corsLookup.put(handlerMethod, corsConfig);
        }
	    // 10.创建 MappingRegistration 对象, 与 mapping 映射添加到 registry 注册表中
        this.registry.put(mapping, new MappingRegistration<>(mapping, handlerMethod, directUrls, name));
    }
    finally {
        this.readWriteLock.writeLock().unlock();
    }
}
5.3.2.4 总结
初始化HandlerMapping时, 扫描有 @Controller 或者 @RequestMapping 注解的类下面的方法, 如果方法上面有 @RequestMapping 注解(包括GetMapping, PostMapping等), 则会为该方法创建对应的 RequestMappingInfo 对象, 将所有的 RequestMappingInfo 对象和 Method 以及方法所在类, 往 MappingRegistry 进行注册, 会生成 HandlerMethod 处理器(Method 所有信息)对象。这样一来, 当 Spring MVC 的 DispatcherServlet 处理请求的时候, 获取到对应的 HandlerMethod 处理器, 就可以通过反射执行对应的方法了

5.3.3 应用

在 DispatcherServlet 的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 {
            // 1.使用MultipartResolver处理文件上传
            processedRequest = checkMultipart(request);
            multipartRequestParsed = (processedRequest != request);

            // 2.根据请求获取到对应的 HandlerExectionChain, HandlerExectionChain是对 HandlerMethod 和 HandlerInterceptor 的封装, HandlerMethod一般是我们使用@RequestMapping注解中对应的方法
            mappedHandler = getHandler(processedRequest);
            if (mappedHandler == null) {
                noHandlerFound(processedRequest, response);
                return;
            }
      ......
}

DispatcherServlet#getHandler

protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
    // 这里 handlerMappings, 默认有三个, 在initHandlerMapping方法中完成初始化并排序, 排序后为
    // RequestMappingHandlerMapping、BeanNameUrlHandlerMapping、SimpleUrlHandlerMapping,
    // 其中第一个 RequestMappingHandlerMapping 就是我们现在常用的用于处理 @RequestMapping 注解方式的 handlerMapping
    if (this.handlerMappings != null) {
        for (HandlerMapping mapping : this.handlerMappings) {
            // 按顺序依次调用 handlerMapping#getHandler 方法, getHandler方法由其父类 AbstractHandlerMapping 实现, 上文已分析
            // HandlerExecutionChain的具体调用后面会分析
            HandlerExecutionChain handler = mapping.getHandler(request);
            if (handler != null) {
                return handler;
            }
        }
    }
    return null;
}

在AbstractHandlerMapping中的getHandler方法,采用模板方法设计模式,回调子类的getHandlerInternal方法,这里我们看 RequestMappingHandlerMapping 的getHandlerInternal方法

RequestMappingHandlerMapping#getHandlerInternal

protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {
    // 1.根据请求获取请求url
    String lookupPath = getUrlPathHelper().getLookupPathForRequest(request);
    // 2.获得读锁
    this.mappingRegistry.acquireReadLock();
    try {
        // 3.【重要】根据请求和url获取对应的HandlerMethod, 见下
        HandlerMethod handlerMethod = lookupHandlerMethod(lookupPath, request);
        // 4.响应
        return (handlerMethod != null ? handlerMethod.createWithResolvedBean() : null);
    }
    finally {
        // 5.释放锁
        this.mappingRegistry.releaseReadLock();
    }
}

RequestMappingHandlerMapping#lookupHandlerMethod

protected HandlerMethod lookupHandlerMethod(String lookupPath, HttpServletRequest request) throws Exception {
    List<Match> matches = new ArrayList<>();
    // 1.首先, 从 urlLookup 属性中找, urlLookup (key --> url, value --> List<RequestMappingInfo>)
    List<T> directPathMatches = this.mappingRegistry.getMappingsByUrl(lookupPath);
    if (directPathMatches != null) {
        // 2.如果找到, 则再根据 RequestMappingInfo 找到对应的 HandlerMethod, 并封装成 Match, 添加到 matches 中
        // 这里会用到 mappingRegistry 的 mappingLookup 属性 (key --> RequestMappingInfo, value --> HandlerMethod)
        addMatchingMappings(directPathMatches, matches, request);
    }
    // 2.这里跳过
    if (matches.isEmpty()) {
        // No choice but to go through all mappings...
        addMatchingMappings(this.mappingRegistry.getMappings().keySet(), matches, request);
    }
	// 3.上述如果匹配到, 则会进行排序, 选择最佳Match
    if (!matches.isEmpty()) {
        Comparator<Match> comparator = new MatchComparator(getMappingComparator(request));
        matches.sort(comparator);
        Match bestMatch = matches.get(0);
        if (matches.size() > 1) {
            if (logger.isTraceEnabled()) {
                logger.trace(matches.size() + " matching mappings: " + matches);
            }
            if (CorsUtils.isPreFlightRequest(request)) {
                return PREFLIGHT_AMBIGUOUS_MATCH;
            }
            Match secondBestMatch = matches.get(1);
            if (comparator.compare(bestMatch, secondBestMatch) == 0) {
                Method m1 = bestMatch.handlerMethod.getMethod();
                Method m2 = secondBestMatch.handlerMethod.getMethod();
                String uri = request.getRequestURI();
                throw new IllegalStateException(
                    "Ambiguous handler methods mapped for '" + uri + "': {" + m1 + ", " + m2 + "}");
            }
        }
        handleMatch(bestMatch.mapping, lookupPath, request);
        return bestMatch.handlerMethod;
    }
    else {
        return handleNoMatch(this.mappingRegistry.getMappings().keySet(), lookupPath, request);
    }
}

5.4 HandlerAdapter

HandlerAdapter组件, 是DispatcherServlet的九大组件之一。在上一步中, 我们通过HandlerMapping组件获取了 HandlerExecutionChain, HandlerExecutionChain 是对对应handler和interceptor的封装, 这里的 handler 是object类型, 需要有一个调用者来实现 handler 是怎么被执行。Spring 中的处理器的有多种实现, 比如用户的处理器可以实现 Controller 接口或者 HttpRequestHandler 接口(这两种方式基本不用了), 也可以用 @RequestMapping 注解将方法作为一个处理器等(这是目前主流的方式), 这就导致 SpringMVC 无法直接执行这个处理器。所以这里需要一个处理器适配器,由它去执行处理器。

5.4.1 初始化

private void initHandlerAdapters(ApplicationContext context) {
    this.handlerAdapters = null;
	
    if (this.detectAllHandlerAdapters) {
        // Find all HandlerAdapters in the ApplicationContext, including ancestor contexts.
        // 1.如果开启探测功能, 则会从springmvc容器中扫描所有的 HandlerAdapter, 添加到 handlerAdapters 中, 默认开启, 默认找到3个
        // 默认3个是何时添加到springmvc容器中?是在初始化子springmvc容器的过程中, 解析springmvc-config.xml配置文件的过程中创建的BeanDefinition, 这个后期有空再具体写文档
        // 这里默认有3个: HttpRequestHandlerAdapter、 SimpleControllerHandlerAdapter、 RequestMappingHandlerAdapter
        Map<String, HandlerAdapter> matchingBeans =
            BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerAdapter.class, true, false);
        if (!matchingBeans.isEmpty()) {
            this.handlerAdapters = new ArrayList<>(matchingBeans.values());
            // We keep HandlerAdapters in sorted order.
            // 排序: HttpRequestHandlerAdapter、 SimpleControllerHandlerAdapter、 RequestMappingHandlerAdapter(重点分析)
            AnnotationAwareOrderComparator.sort(this.handlerAdapters);
        }
    }
    else {
        try {
            HandlerAdapter ha = context.getBean(HANDLER_ADAPTER_BEAN_NAME, HandlerAdapter.class);
            this.handlerAdapters = Collections.singletonList(ha);
        }
        catch (NoSuchBeanDefinitionException ex) {
            // Ignore, we'll add a default HandlerAdapter later.
        }
    }

    // Ensure we have at least some HandlerAdapters, by registering
    // default HandlerAdapters if no other adapters are found.
    if (this.handlerAdapters == null) {
        // 从DispatcherServlet.properties 中获取
        this.handlerAdapters = getDefaultStrategies(context, HandlerAdapter.class);
        if (logger.isTraceEnabled()) {
            logger.trace("No HandlerAdapters declared for servlet '" + getServletName() +
                         "': using default strategies from DispatcherServlet.properties");
        }
    }
}

这里的初始化和 HandlerMapping 的初始化类似,首先从子springmvc容器中获取,即先获取我们在springmvc-config.xml配置文件中配置的 HandlerAdapter以及springmvc容器中自带的(子springmvc容器在初始化时会向容器中注册一些默认的bean, 其中包括一些组件),如果未配置,则获得默认配置 DispatcherServlet.properties 中的 HandlerAdapter 类

5.4.2 实现

5.4.2.1 结构图

5.4.2.2 HandlerAdapter
public interface HandlerAdapter {

    // 使用适配器模式, 判断是否支持当前处理器
    boolean supports(Object handler);

    // 执行处理器, 返回ModelAndView
    @Nullable
    ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception;

    // 返回请求的最新更新时间, 如果不支持该操作, 则返回 -1 即可
    long getLastModified(HttpServletRequest request, Object handler);

}
5.4.2.3 AbstractHandlerMethodAdapter
public abstract class AbstractHandlerMethodAdapter extends WebContentGenerator implements HandlerAdapter, Ordered {
	// 优先级最低
    private int order = Ordered.LOWEST_PRECEDENCE;

    public AbstractHandlerMethodAdapter() {
        // no restriction of HTTP methods by default
        // 参数 restrictDefaultSupportedMethods 参数为 false , 表示不需要严格校验 HttpMethod
        super(false);
    }

    @Override
    public final boolean supports(Object handler) {
        // handler的类型需要是 HandlerMethod, 这个是@RequestMapping配置创建的对应的 HandlerMethod, 且交由子类实现另一个条件
        return (handler instanceof HandlerMethod && supportsInternal((HandlerMethod) handler));
    }

    // 必须同时满足support才成立, 子类一般直接返回true
    protected abstract boolean supportsInternal(HandlerMethod handlerMethod);

    /**
	 * This implementation expects the handler to be an {@link HandlerMethod}.
	 */
    @Override
    @Nullable
    public final ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
        throws Exception {
		// 处理逻辑 , 交给子类实现
        return handleInternal(request, response, (HandlerMethod) handler);
    }

    @Nullable
    protected abstract ModelAndView handleInternal(HttpServletRequest request,
                                                   HttpServletResponse response, HandlerMethod handlerMethod) throws Exception;
    
    @Override
    public final long getLastModified(HttpServletRequest request, Object handler) {
        return getLastModifiedInternal(request, (HandlerMethod) handler);
    }

    protected abstract long getLastModifiedInternal(HttpServletRequest request, HandlerMethod handlerMethod);

}
5.4.2.4 RequestMappingHandlerAdapter
public class RequestMappingHandlerAdapter extends AbstractHandlerMethodAdapter
		implements BeanFactoryAware, InitializingBean {
    ...
}

由上可以看到,其实现了InitializingBean接口,由@spring源码可知,实例化时会回调其afterPropertiesSet方法

RequestMappingHandlerAdapter#afterPropertiesSet

@Override
public void afterPropertiesSet() {
    // Do this first, it may add ResponseBody advice beans
    // 1.初始化 ControllerAdvice 相关
    initControllerAdviceCache();

    // 2.初始化 argumentResolvers 属性
    if (this.argumentResolvers == null) {
        List<HandlerMethodArgumentResolver> resolvers = getDefaultArgumentResolvers();
        this.argumentResolvers = new HandlerMethodArgumentResolverComposite().addResolvers(resolvers);
    }
    // 3.初始化 initBinderArgumentResolvers 属性
    if (this.initBinderArgumentResolvers == null) {
        List<HandlerMethodArgumentResolver> resolvers = getDefaultInitBinderArgumentResolvers();
        this.initBinderArgumentResolvers = new HandlerMethodArgumentResolverComposite().addResolvers(resolvers);
    }
    // 4.初始化 returnValueHandlers 属性
    if (this.returnValueHandlers == null) {
        List<HandlerMethodReturnValueHandler> handlers = getDefaultReturnValueHandlers();
        this.returnValueHandlers = new HandlerMethodReturnValueHandlerComposite().addHandlers(handlers);
    }
}

RequestMappingHandlerAdapter#initControllerAdviceCache

private void initControllerAdviceCache() {
    if (getApplicationContext() == null) {
        return;
    }
	// 1.从spring获取中获取有 @ControllerAdvice 注解的bean, 并封装成 ControllerAdviceBean
    // @ControllerAdvice 通常我们用来做全局异常处理等
    List<ControllerAdviceBean> adviceBeans = ControllerAdviceBean.findAnnotatedBeans(getApplicationContext());
    // 2.排序
    AnnotationAwareOrderComparator.sort(adviceBeans);

    List<Object> requestResponseBodyAdviceBeans = new ArrayList<>();
    // 3.遍历 adviceBeans
    for (ControllerAdviceBean adviceBean : adviceBeans) {
        Class<?> beanType = adviceBean.getBeanType();
        if (beanType == null) {
            throw new IllegalStateException("Unresolvable type for ControllerAdviceBean: " + adviceBean);
        }
        // 扫描有 @ModelAttribute, 没有 @RequestMapping 注解的方法,添加到 modelAttributeAdviceCache 属性中
        // 该类方法用于在执行方法前修改 Model 对象
        Set<Method> attrMethods = MethodIntrospector.selectMethods(beanType, MODEL_ATTRIBUTE_METHODS);
        if (!attrMethods.isEmpty()) {
            this.modelAttributeAdviceCache.put(adviceBean, attrMethods);
        }
        // 扫描有 @InitBinder 注解的方法,添加到 initBinderAdviceCache 属性中
        // 该类方法用于在执行方法前初始化数据绑定器
        Set<Method> binderMethods = MethodIntrospector.selectMethods(beanType, INIT_BINDER_METHODS);
        if (!binderMethods.isEmpty()) {
            this.initBinderAdviceCache.put(adviceBean, binderMethods);
        }
        // 如果是 RequestBodyAdvice 或 ResponseBodyAdvice 的子类, 添加到 requestResponseBodyAdviceBeans 中
        if (RequestBodyAdvice.class.isAssignableFrom(beanType)) {
            requestResponseBodyAdviceBeans.add(adviceBean);
        }
        if (ResponseBodyAdvice.class.isAssignableFrom(beanType)) {
            requestResponseBodyAdviceBeans.add(adviceBean);
        }
    }
	// 将 requestResponseBodyAdviceBeans 添加到 this.requestResponseBodyAdvice 属性
    if (!requestResponseBodyAdviceBeans.isEmpty()) {
        this.requestResponseBodyAdvice.addAll(0, requestResponseBodyAdviceBeans);
    }

    if (logger.isDebugEnabled()) {
        int modelSize = this.modelAttributeAdviceCache.size();
        int binderSize = this.initBinderAdviceCache.size();
        int reqCount = getBodyAdviceCount(RequestBodyAdvice.class);
        int resCount = getBodyAdviceCount(ResponseBodyAdvice.class);
        if (modelSize == 0 && binderSize == 0 && reqCount == 0 && resCount == 0) {
            logger.debug("ControllerAdvice beans: none");
        }
        else {
            logger.debug("ControllerAdvice beans: " + modelSize + " @ModelAttribute, " + binderSize +
                         " @InitBinder, " + reqCount + " RequestBodyAdvice, " + resCount + ", ResponseBodyAdvice");
        }
    }
}

总结

@ControllerAdvice 注解:用于 Controller 类的增强类, 其中可定义多种增强的方法, 例如 @ExceptionHandler 注解的方法用于处理器 Controller 抛出的异常等

RequestMappingHandlerAdapter#handleInternal

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

    ModelAndView mav;
    // 1.请求校验
    checkRequest(request);
	
    // Execute invokeHandlerMethod in synchronized block if required.
    // 2.synchronizeOnSession == false
    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...
        // 3.核心方法
        mav = invokeHandlerMethod(request, response, handlerMethod);
    }

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

    return mav;
}

RequestMappingHandlerAdapter#invokeHandlerMethod

@Nullable
protected ModelAndView invokeHandlerMethod(HttpServletRequest request,
                                           HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
	// 1.创建 ServletWebRequest 对象
    ServletWebRequest webRequest = new ServletWebRequest(request, response);
    try {
        // 2.创建 WebDataBinderFactory 对象
        WebDataBinderFactory binderFactory = getDataBinderFactory(handlerMethod);
        // 3.创建 ModelFactory 对象
        ModelFactory modelFactory = getModelFactory(handlerMethod, binderFactory);
	    // 4.创建 ServletInvocableHandlerMethod 对象, 并设置其相关属性
        ServletInvocableHandlerMethod invocableMethod = createInvocableHandlerMethod(handlerMethod);
        if (this.argumentResolvers != null) {
            invocableMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers);
        }
        if (this.returnValueHandlers != null) {
            invocableMethod.setHandlerMethodReturnValueHandlers(this.returnValueHandlers);
        }
        invocableMethod.setDataBinderFactory(binderFactory);
        invocableMethod.setParameterNameDiscoverer(this.parameterNameDiscoverer);
	    // 5.创建 ModelAndViewContainer 对象, 并初始其相关属性
        ModelAndViewContainer mavContainer = new ModelAndViewContainer();
        mavContainer.addAllAttributes(RequestContextUtils.getInputFlashMap(request));
        modelFactory.initModel(webRequest, mavContainer, invocableMethod);
        mavContainer.setIgnoreDefaultModelOnRedirect(this.ignoreDefaultModelOnRedirect);
        // 6.创建 AsyncWebRequest 异步请求对象
        AsyncWebRequest asyncWebRequest = WebAsyncUtils.createAsyncWebRequest(request, response);
        asyncWebRequest.setTimeout(this.asyncRequestTimeout);
        // 7.创建 WebAsyncManager 异步请求管理器对象
        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();
            LogFormatUtils.traceDebug(logger, traceOn -> {
                String formatted = LogFormatUtils.formatValue(result, !traceOn);
                return "Resume with async result [" + formatted + "]";
            });
            invocableMethod = invocableMethod.wrapConcurrentResult(result);
        }
        // 8.执行, 核心方法, 见下
        invocableMethod.invokeAndHandle(webRequest, mavContainer);
        if (asyncManager.isConcurrentHandlingStarted()) {
            return null;
        }
	    // 9.获得 ModelAndView 对象
        return getModelAndView(mavContainer, modelFactory, webRequest);
    }
    finally {
        webRequest.requestCompleted();
    }
}
5.4.2.5 ServletInvocableHandlerMethod

结构图

ServletInvocableHandlerMethod#invokeAndHandle

public void invokeAndHandle(ServletWebRequest webRequest, ModelAndViewContainer mavContainer,
                            Object... providedArgs) throws Exception {
    // 1.执行方法, 调用的是其父类 InvocableHandlerMethod#invokeForRequest(见下方) 在该方法中, 会回调子类的 doInvoke 方法
    Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs);
    // 2.设置响应状态码
    setResponseStatus(webRequest);
    // 3.设置 ModelAndViewContainer 为请求已处理, 返回, 和 @ResponseStatus 注解相关
    if (returnValue == null) {
        if (isRequestNotModified(webRequest) || getResponseStatus() != null || mavContainer.isRequestHandled()) {
            mavContainer.setRequestHandled(true);
            return;
        }
    }
    else if (StringUtils.hasText(getResponseStatusReason())) {
        mavContainer.setRequestHandled(true);
        return;
    }
    // 4.设置 ModelAndViewContainer 为请求未处理
    mavContainer.setRequestHandled(false);
    Assert.state(this.returnValueHandlers != null, "No return value handlers");
    try {
        // 5.使用 HandlerMethodReturnValueHandler 处理返回值
        // 这里的 returnValueHandlers 为 HandlerMethodReturnValueHandlerComposite 组合对象, 包含了许多的返回值解析器,  采用适配器设计模式, 适配到某个具体的返回值解析器; 
        // 如: 解析 @ResponseBody 参数, 使用的是 RequestResponseBodyMethodProcessor, 参数解析, 需要借助 HttpMessageConverter 
        this.returnValueHandlers.handleReturnValue(
            returnValue, getReturnValueType(returnValue), mavContainer, webRequest);
    }
    catch (Exception ex) {
        if (logger.isTraceEnabled()) {
            logger.trace(formatErrorForReturnValue(returnValue), ex);
        }
        throw ex;
    }
}

InvocableHandlerMethod#invokeForRequest

public Object invokeForRequest(NativeWebRequest request, @Nullable ModelAndViewContainer 			mavContainer, Object... providedArgs) throws Exception {
	// 1.解析请求参数, 见下
    Object[] args = getMethodArgumentValues(request, mavContainer, providedArgs);
    if (logger.isTraceEnabled()) {
        logger.trace("Arguments: " + Arrays.toString(args));
    }
    // 2.回调子类方法
    return doInvoke(args);
}

InvocableHandlerMethod#getMethodArgumentValues

protected Object[] getMethodArgumentValues(NativeWebRequest request, @Nullable 						ModelAndViewContainer mavContainer, Object... providedArgs) throws Exception {
    // 1.获取方法的参数
    MethodParameter[] parameters = getMethodParameters();
    // 2.将参数解析成对应的类型
    Object[] args = new Object[parameters.length];
    for (int i = 0; i < parameters.length; i++) {
        // 获得当前遍历的 MethodParameter 对象,并设置 parameterNameDiscoverer
        MethodParameter parameter = parameters[i];
        parameter.initParameterNameDiscovery(this.parameterNameDiscoverer);
        // 先从 providedArgs 中获得参数。如果获得到, 则进入下一个参数的解析, 默认情况 providedArgs 不会传参
        args[i] = resolveProvidedArgument(parameter, providedArgs);
        if (args[i] != null) {
            continue;
        }
        // 3.判断 resolvers 是否支持当前的参数解析
        // 这里的 argumentResolvers 为 HandlerMethodArgumentResolverComposite 组合对象, 包含了许多的参数解析器, 默认26个, 采用适配器设计模式, 适配到某个具体的参数解析器; 
        // 如: 解析 @RequestBody 参数, 使用的是 RequestResponseBodyMethodProcessor
        // 解析 @RequestParam 参数, 使用的是 RequestParamMethodArgumentResolver
        // 解析 @PathVariable 参数, 使用的是 PathVariableMethodArgumentResolver 
        if (this.argumentResolvers.supportsParameter(parameter)) {
            try {
                // 参数解析, 这里需要借助 HttpMessageConverter 
                args[i] = this.argumentResolvers.resolveArgument(
                    parameter, mavContainer, request, this.dataBinderFactory);
                continue;
            }
            catch (Exception ex) {
                // Leave stack trace for later, e.g. AbstractHandlerExceptionResolver
                if (logger.isDebugEnabled()) {
                    String message = ex.getMessage();
                    if (message != null && !message.contains(parameter.getExecutable().toGenericString())) {
                        logger.debug(formatArgumentError(parameter, message));
                    }
                }
                throw ex;
            }
        }
        if (args[i] == null) {
            throw new IllegalStateException(formatArgumentError(parameter, "No suitable resolver"));
        }
    }
    return args;
}

5.4.3 应用

综上, 在我们最常见的 @RequestMapping 注解类型, 首先会由对应的 HandlerMapping --> RequestMappingHandlerMapping, 获取到对应的HandlerExecutionChain, HandlerExecutionChain封装了的 HandlerMethod 和 HandlerInterceptor, 再由适配器模式根据Handler(这里是HandlerMethod)获取到对应的HandlerAdapter --> RequestMappingHandlerAdapter, 由 RequestMappingHandlerAdapter 执行对应的 HandlerMethod 和 HandlerInterceptor。

具体执行过程:
RequestMappingHandlerAdapter 会先将 HandlerMethod 封装成 ServletInvocableHandlerMethod, 通过 HandlerMethodArgumentResolver 组件解析请求参数,如:通过 RequestResponseBodyMethodProcessor 解析 @RequestBody 参数等; 然后再通过反射机制调用对应的方法(controller中对应的方法), 获取到执行结果后需要通过 HandlerMethodReturnValueHandler 结果处理器来进行处理。

在 HandlerMethodArgumentResolver 解析参数和 HandlerMethodReturnValueHandler 解析返回值的过程中, 会借助 HttpMessageConverter 进行参数解析

5.5 HandlerExceptionResolver

HandlerExceptionResolver是处理器异常解析器,将处理器执行时发生的异常,解析转换成对应的ModelAndView

5.5.1 初始化

private void initHandlerExceptionResolvers(ApplicationContext context) {
    this.handlerExceptionResolvers = null;

    if (this.detectAllHandlerExceptionResolvers) {
        // Find all HandlerExceptionResolvers in the ApplicationContext, including ancestor contexts.
        Map<String, HandlerExceptionResolver> matchingBeans = BeanFactoryUtils
            .beansOfTypeIncludingAncestors(context, HandlerExceptionResolver.class, true, false);
        if (!matchingBeans.isEmpty()) {
            this.handlerExceptionResolvers = new ArrayList<>(matchingBeans.values());
            // We keep HandlerExceptionResolvers in sorted order.
            AnnotationAwareOrderComparator.sort(this.handlerExceptionResolvers);
        }
    }
    else {
        try {
            HandlerExceptionResolver her =
                context.getBean(HANDLER_EXCEPTION_RESOLVER_BEAN_NAME, HandlerExceptionResolver.class);
            this.handlerExceptionResolvers = Collections.singletonList(her);
        }
        catch (NoSuchBeanDefinitionException ex) {
            // Ignore, no HandlerExceptionResolver is fine too.
        }
    }

    // Ensure we have at least some HandlerExceptionResolvers, by registering
    // default HandlerExceptionResolvers if no other resolvers are found.
    if (this.handlerExceptionResolvers == null) {
        this.handlerExceptionResolvers = getDefaultStrategies(context, HandlerExceptionResolver.class);
        if (logger.isTraceEnabled()) {
            logger.trace("No HandlerExceptionResolvers declared in servlet '" + getServletName() +
                         "': using default strategies from DispatcherServlet.properties");
        }
    }
}

初始化的过程和上述组件初始化过程类似,先从springmvc容器中获取相关组件并排序,如果获取失败,则获取 DispatcherServlet.properties 配置文件中的默认配置,这里默认获取3个:ExceptionHandlerExceptionResolver、ResponseStatusExceptionResolver、DefaultHandlerExceptionResolver

5.5.2 应用

DispatcherServlet#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 {
            // 1.判断是否文件上传
            processedRequest = checkMultipart(request);
            multipartRequestParsed = (processedRequest != request);

            // 2.使用HandlerMapping, 获取 HandlerExecutionChain, HandlerExecutionChain 是对 Handler 和 Interceptor的封装
            mappedHandler = getHandler(processedRequest);
            if (mappedHandler == null) {
                noHandlerFound(processedRequest, response);
                return;
            }

            // 3.根据 Handler 找到对应的 HandlerAdapter
            HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());

            // Process last-modified header, if supported by the handler.
            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;
                }
            }
		   // 4.执行相关 Interceptor 的 preHandle
            if (!mappedHandler.applyPreHandle(processedRequest, response)) {
                return;
            }
            
            // 5.执行 Handler
            mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

            if (asyncManager.isConcurrentHandlingStarted()) {
                return;
            }
	
            applyDefaultViewName(processedRequest, mv);
            // 6.执行相关 Interceptor 的 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);
        }
        // 7.处理结果和异常
        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);
            }
        }
    }
}

DispatcherServlet#processDispatchResult

private void processDispatchResult(HttpServletRequest request, HttpServletResponse response,
                                   @Nullable HandlerExecutionChain mappedHandler, @Nullable ModelAndView mv,
                                   @Nullable Exception exception) throws Exception {

    boolean errorView = false;

    if (exception != null) {
        if (exception instanceof ModelAndViewDefiningException) {
            logger.debug("ModelAndViewDefiningException encountered", exception);
            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 (logger.isTraceEnabled()) {
            logger.trace("No view rendering, null ModelAndView returned.");
        }
    }

    if (WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) {
        // Concurrent handling started during a forward
        return;
    }

    if (mappedHandler != null) {
        mappedHandler.triggerAfterCompletion(request, response, null);
    }
}

DispatcherServlet#processHandlerException

@Nullable
protected ModelAndView processHandlerException(HttpServletRequest request, HttpServletResponse response,
      @Nullable Object handler, Exception ex) throws Exception {

   // Success and error responses may use different content types
   request.removeAttribute(HandlerMapping.PRODUCIBLE_MEDIA_TYPES_ATTRIBUTE);

   // 遍历 HandlerExceptionResolver, 解析异常, 生成 ModelAndView 对象
   // ExceptionHandlerExceptionResolver、ResponseStatusExceptionResolver、DefaultHandlerExceptionResolver
   // ExceptionHandlerExceptionResolver 是基于 @ExceptionHandler 注解来配置对应的异常处理器
   ModelAndView exMv = null;
   if (this.handlerExceptionResolvers != null) {
      for (HandlerExceptionResolver resolver : this.handlerExceptionResolvers) {
         exMv = resolver.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()) {
         String defaultViewName = getDefaultViewName(request);
         if (defaultViewName != null) {
            exMv.setViewName(defaultViewName);
         }
      }
      if (logger.isTraceEnabled()) {
         logger.trace("Using resolved error view: " + exMv, ex);
      }
      if (logger.isDebugEnabled()) {
         logger.debug("Using resolved error view: " + exMv);
      }
      WebUtils.exposeErrorRequestAttributes(request, ex, getServletName());
      return exMv;
   }

   throw ex;
}

5.6 RequestToViewNameTranslator

5.6.1 初始化

private void initRequestToViewNameTranslator(ApplicationContext context) {
    try {
        this.viewNameTranslator =
            context.getBean(REQUEST_TO_VIEW_NAME_TRANSLATOR_BEAN_NAME, RequestToViewNameTranslator.class);
        if (logger.isTraceEnabled()) {
            logger.trace("Detected " + this.viewNameTranslator.getClass().getSimpleName());
        }
        else if (logger.isDebugEnabled()) {
            logger.debug("Detected " + this.viewNameTranslator);
        }
    }
    catch (NoSuchBeanDefinitionException ex) {
        // We need to use the default.
        this.viewNameTranslator = getDefaultStrategy(context, RequestToViewNameTranslator.class);
        if (logger.isTraceEnabled()) {
            logger.trace("No RequestToViewNameTranslator '" + REQUEST_TO_VIEW_NAME_TRANSLATOR_BEAN_NAME +
                         "': using default [" + this.viewNameTranslator.getClass().getSimpleName() + "]");
        }
    }
}

初始化的过程和上述组件初始化过程类似,先从springmvc容器中获取相关组件并排序,如果获取失败,则获取 DispatcherServlet.properties 配置文件中的默认配置,这里默认获取1个:DefaultRequestToViewNameTranslator

5.6.2 应用

在 DispatcherServlet #doDispatch方法中,调用了applyDefaultViewName

DispatcherServlet#applyDefaultViewName

private void applyDefaultViewName(HttpServletRequest request, @Nullable ModelAndView mv) throws Exception {
    if (mv != null && !mv.hasView()) {
        // 使用 DefaultRequestToViewNameTranslator 获取viewName
        String defaultViewName = getDefaultViewName(request);
        if (defaultViewName != null) {
            mv.setViewName(defaultViewName);
        }
    }
}

DefaultRequestToViewNameTranslator#getViewName

public String getViewName(HttpServletRequest request) {
    String lookupPath = this.urlPathHelper.getLookupPathForRequest(request);
    return (this.prefix + transformPath(lookupPath) + this.suffix);
}

5.7 LocaleResolver

LocaleResolver 组件, 本地化(国际化)解析器, 提供国际化支持, 这里暂略

5.8 ViewResolver

ViewResolver 组件, 是试图解析器, 这里暂略

注解版

0.准备阶段

WebAppInitializer

public class WebAppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
    @Override
    protected Class<?>[] getRootConfigClasses() {
        return new Class[]{RootConfig.class};
    }

    @Override
    protected Class<?>[] getServletConfigClasses() {
        return new Class[]{WebConfig.class};
    }

    @Override
    protected String[] getServletMappings() {
        return new String[]{"/"};
    }
}

config

// 这个是根容器, 相当于ApplicationContext.xml, 包扫描的时候要排除@Controller注解, 避免重复扫描
@ComponentScan(value ={"com.tca"},
        excludeFilters={@ComponentScan.Filter(type = FilterType.ANNOTATION,value = {Controller.class})})
public class RootConfig {
}
// 这个是子容器, 相当于springmvc-config.xml, 只扫描@Controller注解, 避免重复扫描
@EnableWebMvc
@Configuration
@ComponentScan(value = {"com.tca"}, includeFilters={@ComponentScan.Filter(
        type= FilterType.ANNOTATION, value={Controller.class})}, useDefaultFilters = false)
public class WebConfig {
}

controller

@RequestMapping("/hello")
@Controller
public class HelloController {

    @Autowired
    private HelloService helloService;

    @GetMapping("/test")
    @ResponseBody
    public String test() {
        return helloService.test();
    }
}

service

@Service
public class HelloService {

    public String test() {
        return "test";
    }
}

1.Servlet3.0

1.1 servlet3.0规范

目的

servlet3.0规范主要是用于去web.xml化, 使用纯注解的方式

实现

实现servlet3.0规范的servlet容器(如tomcat),必须实现以下规范

1.servlet容器(如tomcat)启动时会扫描当前应用里所有的jar中ServletContainerInitializer的实现类
2.当前jar中ServletContainerInitializer的实现类, 需要绑定在当前jar下resource目录下的META_INF/services/javax.servlet.ServletContainerInitializer文件, 文件里内容是ServletContainerInitializer实现类的全类名
3.自定义ServletContainerInitializer的实现上可以添加@HandlesTypes注解, 注解中可以传入一些class/interface, 这些class/interface的所有子类实现都会作为onStartup方法的参数
4.在onstart方法中, 我们可以向servlet容器中注册web三大组件: Listener(监听器), Filter(过滤器), Servlet, 完美替代了web.xml的作用

总结

容器启动时会扫描所有jar中的META_INF/services/javax.servlet.ServletContainerInitializer文件, 实例化文件中的类, 并调用onStartup方法(SPI机制)

2.springmvc注解版对servlet3.0规范的适配

2.1 实现

1.spring-web的jar中, 在 resource/META_INF/services/javax.servlet.ServletContainerInitializer 目录下, 有一个ServletContainerInitializer的实现类:
org.springframework.web.SpringServletContainerInitializer
2.SpringServletContainerInitializer配置了@HandlesTypes注解, 指定了WebApplicationInitializer接口
3.容器启动时, 会调用SpringServletContainerInitializer的onStartup方法, 方法的参数有两个: 一是WebApplicationInitializer的所有实现类对应的Class对象, 另一个是ServletContext

2.2 SpringServletContainerInitializer

SpringServletContainerInitializer上注解:@HandlesTypes(WebApplicationInitializer.class)

SpringServletContainerInitializer#onStartup(@Nullable Set<Class<?>> webAppInitializerClasses, ServletContext servletContext)

根据上述,servlet容器(tomcat)启动时调用ServletContainerInitializer实现类的onStartup方法

@Override
public void onStartup(@Nullable Set<Class<?>> webAppInitializerClasses, ServletContext servletContext)
    throws ServletException {

    List<WebApplicationInitializer> initializers = new LinkedList<>();
	// 1.获取所有的 WebApplicationInitializer 接口的实现类Class对象, 这里有5个:
    // AbstractContextLoaderInitializer
    // AbstractDispatcherServletInitializer
    // AbstractAnnotationConfigDispatcherServletInitializer
    // WebAppInitializer
    // AbstractReactiveWebInitializer
    if (webAppInitializerClasses != null) {
        for (Class<?> waiClass : webAppInitializerClasses) {
            // 2.这里只有自定义的WebAppInitializer不是接口和抽象类
            if (!waiClass.isInterface() && !Modifier.isAbstract(waiClass.getModifiers()) &&
                WebApplicationInitializer.class.isAssignableFrom(waiClass)) {
                try {
                    // 3.实例化 WebAppInitializer
                    initializers.add((WebApplicationInitializer)
                                     ReflectionUtils.accessibleConstructor(waiClass).newInstance());
                }
                catch (Throwable ex) {
                    throw new ServletException("Failed to instantiate WebApplicationInitializer class", ex);
                }
            }
        }
    }

    if (initializers.isEmpty()) {
        servletContext.log("No Spring WebApplicationInitializer types detected on classpath");
        return;
    }

    servletContext.log(initializers.size() + " Spring WebApplicationInitializers detected on classpath");
    AnnotationAwareOrderComparator.sort(initializers);
    // 4.调用onStartUp方法
    for (WebApplicationInitializer initializer : initializers) {
        initializer.onStartup(servletContext);
    }
}

2.3 WebAppInitializer

2.3.1 结构图

2.3.2 启动流程

1.调用WebAppInitializer的onStartup方法,该方法其父类AbstractDispatcherServletInitializer、AbstractContextLoaderInitializer都有实现,首先调用AbstractDispatcherServletInitializer#onStartup方法

AbstractDispatcherServletInitializer#onStartup(ServletContext servletContext)
@Override
public void onStartup(ServletContext servletContext) throws ServletException {
    // 1.先调用其父类 AbstractContextLoaderInitializer 的onStartup方法, 用于初始化父Spring容器, 添加监听器等操作
    super.onStartup(servletContext);
    // 2.这里创建springmvc容器, 向容器中注册DispatcherServlet, 注册Filter等
    registerDispatcherServlet(servletContext);
}

AbstractDispatcherServletInitializer#registerDispatcherServlet(ServletContext servletContext)

protected void registerDispatcherServlet(ServletContext servletContext) {
    // 1.获取当前servletName, 这里是dispatcher
    String servletName = getServletName();
    Assert.hasLength(servletName, "getServletName() must not return null or empty");
	// 2.创建springmvc子容器, 这里回调用getServletConfigClasses()方法, 获取springmvc的主配置,  该方法由子类 WebAppInitializer 实现, 这里返回
    // WebConfig.class
    WebApplicationContext servletAppContext = createServletApplicationContext();
    Assert.notNull(servletAppContext, "createServletApplicationContext() must not return null");
	// 3.创建DispatcherServlet
    FrameworkServlet dispatcherServlet = createDispatcherServlet(servletAppContext);
    Assert.notNull(dispatcherServlet, "createDispatcherServlet(WebApplicationContext) must not return null");
    dispatcherServlet.setContextInitializers(getServletApplicationContextInitializers());
	// 4.将DispatcherServlet添加到 servletContext容器中, 这里完成了web.xml文件中<servlet>-DispatcherServlet的配置
    ServletRegistration.Dynamic registration = servletContext.addServlet(servletName, dispatcherServlet);
    if (registration == null) {
        throw new IllegalStateException("Failed to register servlet with name '" + servletName + "'. " +
                                        "Check if there is another servlet registered under the same name.");
    }
    registration.setLoadOnStartup(1);
    // 5.这里调用 getServletMappings(), 获取DispatcherServlet拦截的请求, 该方法由子类 WebAppInitializer 实现, 这里返回 "/"
    registration.addMapping(getServletMappings());
    registration.setAsyncSupported(isAsyncSupported());
    // 6.这里我们可以实现 getServletFilters() 方法, 向servletContext中注册 Filter
    Filter[] filters = getServletFilters();
    if (!ObjectUtils.isEmpty(filters)) {
        for (Filter filter : filters) {
            registerServletFilter(servletContext, filter);
        }
    }

    customizeRegistration(registration);
}
AbstractContextLoaderInitializer#onStartup(ServletContext servletContext)
@Override
public void onStartup(ServletContext servletContext) throws ServletException {
    registerContextLoaderListener(servletContext);
}

AbstractContextLoaderInitializer#registerContextLoaderListener(ServletContext servletContext)

protected void registerContextLoaderListener(ServletContext servletContext) {
    // 1.初始化父spring容器, 调用createRootApplicationContext()方法时, 会调用getRootConfigClasses(), 用于获取父容器的主配置类, 
    // getRootConfigClasses()被子类 WebAppInitializer复写, 这里返回了RootConfig.class 
    WebApplicationContext rootAppContext = createRootApplicationContext();
    if (rootAppContext != null) {
        // 2.初始化 ContextLoaderListener 监听器
        ContextLoaderListener listener = new ContextLoaderListener(rootAppContext);
        listener.setContextInitializers(getRootApplicationContextInitializers());
        // 3.servletContext中添加监听器 ContextLoaderListener, 这里就替代了web.xml中<listener>标签作用
        servletContext.addListener(listener);
    }
    else {
        logger.debug("No ContextLoaderListener registered, as " +
                     "createRootApplicationContext() did not return an application context");
    }
}

2.4 总结

1.spring-web的jar中, 在 resource/META_INF/services/javax.servlet.ServletContainerInitializer 目录下, 有一个ServletContainerInitializer的实现类:
org.springframework.web.SpringServletContainerInitializer
2.SpringServletContainerInitializer配置了@HandlesTypes注解, 指定了WebApplicationInitializer接口
3.容器启动时, 会调用SpringServletContainerInitializer的onStartup方法, 方法的参数有两个: 一是WebApplicationInitializer的所有实现类对应的Class对象, 另一个是ServletContext; 这里 WebApplicationInitializer的实现类只有一个: WebAppInitializer(自定义的)
4.调用其onStartup方法时会完成父spring容器的创建, 子spring容器的创建, 以及完成DispatcherServlet的创建并注册到spring容器中, 添加监听器, 过滤器等

原文来自:https://gitee.com/tca/springmvc-configfile/blob/master/SpringMVC%E6%BA%90%E7%A0%81%E8%A7%A3%E6%9E%90.md