Spring MVC 从实例读源码

来源:互联网 发布:mmap文件阅读器 mac 编辑:程序博客网 时间:2024/06/08 18:53

Spring MVC 从实例读源码

更为完整的笔记传送门 Github

实例-MVC

IndexController

@Controllerpublic class IndexController {    @RequestMapping("/hello")    public ModelAndView index(ModelAndView modelAndView){        modelAndView.addObject("user",new RegisterDTO("admin"));        modelAndView.setViewName("hello");        return modelAndView;    }}

hello.jsp

<body>    <h1>Hello World!</h1>    ${requestScope.user.username}</body>

web.xml

<context-param>    <param-name>contextConfigLocation</param-name>    <param-value>classpath*:spring/spring-*.xml</param-value></context-param><listener>    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class></listener><servlet>    <servlet-name>springDispatcherServlet</servlet-name>    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>    <init-param>        <param-name>contextConfigLocation</param-name>        <param-value>classpath:spring/spring-web.xml</param-value>    </init-param></servlet><servlet-mapping>    <servlet-name>springDispatcherServlet</servlet-name>    <url-pattern>/</url-pattern></servlet-mapping>

约定

方法调用顺序约定

这里用 1.1) 、1.2) 来表示1)方法中的比较重要的步骤1和步骤2。
另外并不是从一开始就进行编号,而是到重要的方法时才开始编号。

public class Main {    public static void main(String[] args) {        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");        UserService userService = (UserService) applicationContext.getBean("userService");        userService.login();    }}

比如Main类中的main方法记为1),则可以将new ClassPathXmlApplicationContext记为1.1),将getBean记为1.2)。

实例-REST

@RequestMapping("/users/{name}")@ResponseBodypublic RegisterDTO findUserByName(@PathVariable("name") String name){    return new RegisterDTO(name);}

关注点约束

我们只关注源码中的核心的业务逻辑,由于Spring过于复杂,所以哪怕只掌握其核心逻辑就很不容易了。另外文章是从实例看源码的,所以可能源码中有多条执行路径,但我们只关注实例中经过的逻辑,其他的执行路径可能会被忽略。

Spring MVC概述

Spring MVC是Spring对Web环境的支持,并提供了MVC模型简化编程。Spring MVC仍然使用BeanFactory,只是在原有基础上添加了web支持,使用到的是WebApplicationContext。Spring MVC源码可以分为三个部分,分别是初始化ApplicationContext,初始化DispatcherServlet和处理请求。
初始化ApplicationContext与非web环境的Spring不同,不是直接new一个ApplicationContext,而是通过ServletContextListener留的初始化接口进行初始化ApplicationContext的。

Spring MVC本质上是对原生ServletAPI的封装,所有请求都先被发送到DispatcherServlet,这就会触发DispatcherServlet的初始化,其中会对ApplicationContext进行进一步的初始化。

处理请求则是描述了一个请求从发送给DispatcherServlet,到路由到编写的Controller,最后进行页面跳转整个过程。

阅读Spring MVC源码最好是阅读过Spring IOC的源码,因为它们涉及到的ApplicationContext(ClassPathXmlApplicationContext、WebApplicationContext)本质上都是BeanFactory的实现。

初始化ApplicationContext

这里写图片描述

ContextLoaderListener(入口)

ContextLoaderListener的作用就是启动Web容器时,自动装配ApplicationContext的配置信息。
因为它实现了ServletContextListener这个接口,在web.xml配置这个监听器,启动容器时,就会默认执行它实现的方法,使用ServletContextListener接口,开发者能够在为客户端请求提供服务之前向ServletContext中添加任意的对象。
在ServletContextListener中的核心逻辑是初始化WebApplicationContext实例并存放在ServletContext中。

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

ContextLoader.initWebApplicationContext

public WebApplicationContext initWebApplicationContext(ServletContext servletContext) {   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.      if (this.context == null) {// 创建WebApplicationContext         this.context = createWebApplicationContext(servletContext);      }      if (this.context instanceof ConfigurableWebApplicationContext) {         ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext) this.context;         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 ->               // determine parent for root web application context, if any.               ApplicationContext parent = loadParentContext(servletContext);               cwac.setParent(parent);            }            configureAndRefreshWebApplicationContext(cwac, servletContext);         }      }      // 记录在ServletContext中 servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, this.context);      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");      }      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;   }}

ContextLoader.createWebApplicationContext(创建WebApplicationContext实例)

protected WebApplicationContext createWebApplicationContext(ServletContext sc) {   Class<?> contextClass = determineContextClass(sc);   if (!ConfigurableWebApplicationContext.class.isAssignableFrom(contextClass)) {      throw new ApplicationContextException("Custom context class [" + contextClass.getName() +            "] is not of type [" + ConfigurableWebApplicationContext.class.getName() + "]");   }   return (ConfigurableWebApplicationContext) BeanUtils.instantiateClass(contextClass);}

determineContextClass

protected Class<?> determineContextClass(ServletContext servletContext) {   String contextClassName = servletContext.getInitParameter(CONTEXT_CLASS_PARAM);// 如果在web.xml中配置了contextClass,则直接加载这个类   if (contextClassName != null) {      try {         return ClassUtils.forName(contextClassName, ClassUtils.getDefaultClassLoader());      }      catch (ClassNotFoundException ex) {         throw new ApplicationContextException(               "Failed to load custom context class [" + contextClassName + "]", ex);      }   }   else {// 否则使用默认值      contextClassName = defaultStrategies.getProperty(WebApplicationContext.class.getName());      try {         return ClassUtils.forName(contextClassName, ContextLoader.class.getClassLoader());      }      catch (ClassNotFoundException ex) {         throw new ApplicationContextException(               "Failed to load default context class [" + contextClassName + "]", ex);      }   }}

看defaultStrategies是怎么初始化的

static {   // Load default strategy implementations from properties file.   // This is currently strictly internal and not meant to be customized   // by application developers.   try {      ClassPathResource resource = new ClassPathResource(DEFAULT_STRATEGIES_PATH, ContextLoader.class);      defaultStrategies = PropertiesLoaderUtils.loadProperties(resource);   }   catch (IOException ex) {      throw new IllegalStateException("Could not load 'ContextLoader.properties': " + ex.getMessage());   }}private static final String DEFAULT_STRATEGIES_PATH = "ContextLoader.properties";

在ContextLoader目录下有一个配置文件ContextLoader.properties
内容为:

org.springframework.web.context.WebApplicationContext=org.springframework.web.context.support.XmlWebApplicationContext

在初始化过程中,程序首先会读取ContextLoader类的同目录下的配置文件ContextLoader.properties,并根据其中的配置提取将要实现WebApplicationContext接口的实现类,并根据这个实现类通过反射的方式进行实例的创建。

初始化DispatcherServlet

这里写图片描述
第一次访问网站时,会初始化访问到的servlet。
初始化阶段会调用servlet的init方法,在DispatcherServlet中是由其父类HttpServletBean实现的。
init
逻辑:
1)封装及验证初始化参数
2)将当前servlet实例转化为BeanWrapper实例
3)注册相对于Resource的属性编辑器
4)属性注入
5)servletBean的初始化

public final void init() throws ServletException {   if (logger.isDebugEnabled()) {      logger.debug("Initializing servlet '" + getServletName() + "'");   }   // Set bean properties from init parameters.   try {// 解析init-param并封装到PropertyValues中      PropertyValues pvs = new ServletConfigPropertyValues(getServletConfig(), this.requiredProperties);// 把当前的servlet类转化为一个BeanWrapper,从而能够以Spring的方式来对init-param的值进行注入      BeanWrapper bw = PropertyAccessorFactory.forBeanPropertyAccess(this);      ResourceLoader resourceLoader = new ServletContextResourceLoader(getServletContext());// 设置自定义属性编辑器,如果遇到Resource类型的属性将会使用ResourceEditor进行解析      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.// 留给子类扩展   initServletBean();   if (logger.isDebugEnabled()) {      logger.debug("Servlet '" + getServletName() + "' configured successfully");   }}

1)ServletConfigPropertyValues

private static class ServletConfigPropertyValues extends MutablePropertyValues {   /**    * Create new ServletConfigPropertyValues.    * @param config ServletConfig we'll use to take PropertyValues from    * @param requiredProperties set of property names we need, where    * we can't accept default values    * @throws ServletException if any required properties are missing    */   public ServletConfigPropertyValues(ServletConfig config, Set<String> requiredProperties)      throws ServletException {      Set<String> missingProps = (requiredProperties != null && !requiredProperties.isEmpty() ?            new HashSet<String>(requiredProperties) : null);      Enumeration<String> paramNames = config.getInitParameterNames();      while (paramNames.hasMoreElements()) {         String property = paramNames.nextElement();         Object value = config.getInitParameter(property);         addPropertyValue(new PropertyValue(property, value));         if (missingProps != null) {            missingProps.remove(property);         }      }      // Fail if we are still missing properties.      if (!CollectionUtils.isEmpty(missingProps)) {         throw new ServletException(            "Initialization from ServletConfig for servlet '" + config.getServletName() +            "' failed; the following required properties were missing: " +            StringUtils.collectionToDelimitedString(missingProps, ", "));      }   }}

2)FrameworkServlet.initServletBean(对WebApplicationContext实例补充初始化)

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 {      this.webApplicationContext = initWebApplicationContext();// 留给子类覆盖      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");   }}

2.1)FrameworkServlet.initWebApplicationContext

创建或刷新WebApplicationContext实例,并对servlet功能所使用的变量进行初始化

逻辑:
1)寻找或创建对应的WebApplicationContext实例
①通过构造函数的注入进行初始化
②通过contextAttribute进行初始化
通过在web.xml中配置的servlet参数contextAttribute来查找ServletContext中对应的属性,默认为WebApplicationContext.class.getName() + “.ROOT”,也就是在ContextLoaderListener加载时会创建WebApplicationContext实例,并将实例以
WebApplicationContext.class.getName() + “.ROOT”为key放入ServletContext中。
③ 重新创建WebApplicationContext实例
2)对已经创建的WebApplicationContext实例进行配置和刷新
3)刷新Spring在Web功能实现中必须使用的全局变量

protected WebApplicationContext initWebApplicationContext() {   WebApplicationContext rootContext =         WebApplicationContextUtils.getWebApplicationContext(getServletContext());   WebApplicationContext wac = null;   if (this.webApplicationContext != null) {// applicationContext实例在构造函数中被注入      // A context instance was injected at construction time -> use it      wac = this.webApplicationContext;      if (wac instanceof ConfigurableWebApplicationContext) {         ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext) wac;         if (!cwac.isActive()) {            // The context has not yet been refreshed -> provide services such as            // setting the parent context, setting the application context id, etc            if (cwac.getParent() == null) {               // The context instance was injected without an explicit parent -> set               // the root application context (if any; may be null) as the parent               cwac.setParent(rootContext);            }// 刷新上下文环境            configureAndRefreshWebApplicationContext(cwac);         }      }   }   if (wac == null) {      // No context instance was injected at construction time -> see if one      // has been registered in the servlet context. If one exists, it is assumed      // that the parent context (if any) has already been set and that the      // user has performed any initialization such as setting the context id    // 根据contextAttribute属性加载WebApplicationContext       wac = findWebApplicationContext();   }   if (wac == null) {      // No context instance is defined for this servlet -> create a local one // 重新创建WebApplicationContext      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.// 刷新Spring在web功能实现中必须使用的全局变量      onRefresh(wac);   }   if (this.publishContext) {      // Publish the context as a servlet context attribute.      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;}
2.1.1) (与IOC衔接)configureAndRefreshWebApplicationContext
protected void configureAndRefreshWebApplicationContext(ConfigurableWebApplicationContext wac) {   if (ObjectUtils.identityToString(wac).equals(wac.getId())) {      // The application context id is still set to its original default value      // -> assign a more useful id based on available information      if (this.contextId != null) {         wac.setId(this.contextId);      }      else {         // Generate default id...         wac.setId(ConfigurableWebApplicationContext.APPLICATION_CONTEXT_ID_PREFIX +               ObjectUtils.getDisplayString(getServletContext().getContextPath()) + '/' + getServletName());      }   }   wac.setServletContext(getServletContext());   wac.setServletConfig(getServletConfig());   wac.setNamespace(getNamespace());   wac.addApplicationListener(new SourceFilteringListener(wac, new ContextRefreshListener()));   // The wac environment's #initPropertySources will be called in any case when the context   // is refreshed; do it eagerly here to ensure servlet property sources are in place for   // use in any post-processing or initialization that occurs below prior to #refresh   ConfigurableEnvironment env = wac.getEnvironment();   if (env instanceof ConfigurableWebEnvironment) {      ((ConfigurableWebEnvironment) env).initPropertySources(getServletContext(), getServletConfig());   }   postProcessWebApplicationContext(wac);   applyInitializers(wac);// 加载配置文件以及整合parent到wac(就是ApplicationContext中的refresh方法)   wac.refresh();}

这里调用了refresh方法,如果看过Spring IOC源码,那么会意识到这个就是初始化BeanFactory的refresh方法。

2.1.2) findWebApplicationContext
protected WebApplicationContext findWebApplicationContext() {   String attrName = getContextAttribute();   if (attrName == null) {      return null;   }   WebApplicationContext wac =         WebApplicationContextUtils.getWebApplicationContext(getServletContext(), attrName);   if (wac == null) {      throw new IllegalStateException("No WebApplicationContext found: initializer not registered?");   }   return wac;}
2.1.3) FrameworkServlet.createWebApplicationContext
protected WebApplicationContext createWebApplicationContext(ApplicationContext parent) {// 获取servlet的初始化参数contextClass,如果没有配置默认为XMLWebApplicationContext.class   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");   }// 通过反射实例化contextClass   ConfigurableWebApplicationContext wac =         (ConfigurableWebApplicationContext) BeanUtils.instantiateClass(contextClass);   wac.setEnvironment(getEnvironment());// parent为在ContextLoaderListener中创建的实例   wac.setParent(parent);// 获取contextConfigLocation属性,配置在servlet初始化参数中   wac.setConfigLocation(getContextConfigLocation());   // 初始化Spring环境包括加载配置文件等(即为2.1.1)   configureAndRefreshWebApplicationContext(wac);   return wac;}
2.1.4) DispatcherServlet.onRefresh
protected void onRefresh(ApplicationContext context) {   initStrategies(context);}

HandlerMapping:请求和处理器之间的映射,用于获取HandlerExecutionChain
HandlerAdapter:实际的请求处理器,处理后返回ModelAndView
HandlerExceptionResolver:异常处理器,当拦截器的postHandle方法调用后检查异常。
ViewResolver:视图解析器,解析视图名,得到View,由逻辑视图变为物理视图。

protected void initStrategies(ApplicationContext context) {// 初始化文件上传模块   initMultipartResolver(context);// 初始化国际化模块   initLocaleResolver(context);// 初始化主题模块   initThemeResolver(context);// 初始化HandlerMappings   initHandlerMappings(context);// 初始化HandlerAdapters   initHandlerAdapters(context);// 初始化HandlerExceptionResolvers   initHandlerExceptionResolvers(context);   initRequestToViewNameTranslator(context);// 初始化ViewResolvers   initViewResolvers(context);   initFlashMapManager(context);}
2.1.4.1) initHandlerMappings

当客户端发出Request时DispatcherServlet会将Request提交给HandlerMapping,然后HandlerMapping根据WebApplicationContext的配置,回传给DispatcherServlet相应的Controller。
在基于SpringMVC的web应用程序中,我们可以为DispatcherServlet提供多个HandlerMapping供其使用。DispatcherServlet在选用HandlerMapping的过程中,将根据我们所指定的一系列HandlerMapping的优先级进行排序,然后优先使用优先级在前的HandlerMapping。如果当前的HandlerMapping能够返回可用的Handler,则使用当前的Handler进行Web请求的处理,而不再继续询问其他的HandlerMapping。否则,将继续按照各个HandlerMapping的优先级询问,直到获取一个可用的Handler为止。

默认情况下,SpringMVC将加载当前系统中所有实现了HandlerMapping接口的bean。如果只期望SpringMVC加载指定的handlerMapping时,可以修改web.xml中的DispatcherServlet的初始参数,将detectAllHandlerMappings的值设置为false。
此时,SpingMVC将查找名为handlerMapping的bean,并作为当前系统中唯一的handlerMapping。如果没有定义handlerMapping的话,则SpringMVC将按照DispatcherServlet所在目录下的DispatcherServlet.properties中所定义的内容来加载默认的handlerMapping。

private void initHandlerMappings(ApplicationContext context) {   this.handlerMappings = null;   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<HandlerMapping>(matchingBeans.values());         // We keep HandlerMappings in sorted order.         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");      }   }}

默认的handlerMappings有
org.springframework.web.servlet.HandlerMapping=org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping, org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping

getBean时会调用afterPropertiesSet

public void afterPropertiesSet() {   initHandlerMethods();}
2.1.4.1.1) AbstractHandlerMethodMapping.initHandlerMethods
protected void initHandlerMethods() {   if (logger.isDebugEnabled()) {      logger.debug("Looking for request mappings in application context: " + getApplicationContext());   }   String[] beanNames = (this.detectHandlerMethodsInAncestorContexts ?         BeanFactoryUtils.beanNamesForTypeIncludingAncestors(getApplicationContext(), Object.class) :         getApplicationContext().getBeanNamesForType(Object.class));   for (String beanName : beanNames) {      if (!beanName.startsWith(SCOPED_TARGET_NAME_PREFIX)) {         Class<?> beanType = null;         try {            beanType = getApplicationContext().getType(beanName);         }         catch (Throwable ex) {            // An unresolvable bean type, probably from a lazy bean - let's ignore it.            if (logger.isDebugEnabled()) {               logger.debug("Could not resolve target class for bean with name '" + beanName + "'", ex);            }         }         if (beanType != null && isHandler(beanType)) {            detectHandlerMethods(beanName);         }      }   }   handlerMethodsInitialized(getHandlerMethods());}
2.1.4.1.1.1) detectHandlerMethods
protected void detectHandlerMethods(final Object handler) {   Class<?> handlerType = (handler instanceof String ?         getApplicationContext().getType((String) handler) : handler.getClass());   final Class<?> userType = ClassUtils.getUserClass(handlerType);   Map<Method, T> methods = MethodIntrospector.selectMethods(userType,         new MethodIntrospector.MetadataLookup<T>() {            @Override            public T inspect(Method method) {               try {                  return getMappingForMethod(method, userType);               }               catch (Throwable ex) {                  throw new IllegalStateException("Invalid mapping on handler class [" +                        userType.getName() + "]: " + method, ex);               }            }         });   if (logger.isDebugEnabled()) {      logger.debug(methods.size() + " request handler methods found on " + userType + ": " + methods);   }   for (Map.Entry<Method, T> entry : methods.entrySet()) {      Method invocableMethod = AopUtils.selectInvocableMethod(entry.getKey(), userType);      T mapping = entry.getValue();      registerHandlerMethod(handler, invocableMethod, mapping);   }}
2.1.4.1.1.1.1) registerHandlerMethod
protected void registerHandlerMethod(Object handler, Method method, T mapping) {   this.mappingRegistry.register(mapping, handler, method);}
2.1.4.1.1.1.1.1) MappingRegistry.register
public void register(T mapping, Object handler, Method method) {   this.readWriteLock.writeLock().lock();   try {      HandlerMethod handlerMethod = createHandlerMethod(handler, method);      assertUniqueMethodMapping(handlerMethod, mapping);      if (logger.isInfoEnabled()) {         logger.info("Mapped \"" + mapping + "\" onto " + handlerMethod);      }      this.mappingLookup.put(mapping, handlerMethod);      List<String> directUrls = getDirectUrls(mapping);      for (String url : directUrls) {         this.urlLookup.add(url, mapping);      }      String name = null;      if (getNamingStrategy() != null) {         name = getNamingStrategy().getName(handlerMethod, mapping);         addMappingName(name, handlerMethod);      }      CorsConfiguration corsConfig = initCorsConfiguration(handler, method, mapping);      if (corsConfig != null) {         this.corsLookup.put(handlerMethod, corsConfig);      }      this.registry.put(mapping, new MappingRegistration<T>(mapping, handlerMethod, directUrls, name));   }   finally {      this.readWriteLock.writeLock().unlock();   }}
2.1.4.2) initHandlerAdapters

detectAllHandlerAdapters这个变量和detectAllHandlerMappings作用差不多。

private void initHandlerAdapters(ApplicationContext context) {   this.handlerAdapters = null;   if (this.detectAllHandlerAdapters) {      // Find all HandlerAdapters in the ApplicationContext, including ancestor contexts.      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.         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");      }   }}

getDefaultStrategies(context, HandlerAdapter.class)
defaultStrategies是从配置文件DispatcherServlet.properties中加载得到的。
默认有以下HandlerAdapter:
org.springframework.web.servlet.HandlerAdapter=org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter, org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter, org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter

protected <T> List<T> getDefaultStrategies(ApplicationContext context, Class<T> strategyInterface) {   String key = strategyInterface.getName();   String value = defaultStrategies.getProperty(key);   if (value != null) {      String[] classNames = StringUtils.commaDelimitedListToStringArray(value);      List<T> strategies = new ArrayList<T>(classNames.length);      for (String className : classNames) {         try {            Class<?> clazz = ClassUtils.forName(className, DispatcherServlet.class.getClassLoader());            Object strategy = createDefaultStrategy(context, clazz);            strategies.add((T) strategy);         }         catch (ClassNotFoundException ex) {            throw new BeanInitializationException(                  "Could not find DispatcherServlet's default strategy class [" + className +                        "] for interface [" + key + "]", ex);         }         catch (LinkageError err) {            throw new BeanInitializationException(                  "Error loading DispatcherServlet's default strategy class [" + className +                        "] for interface [" + key + "]: problem with class file or dependent class", err);         }      }      return strategies;   }   else {      return new LinkedList<T>();   }}

Spring中所使用的Handler并没有任何特殊的联系,为了统一处理,Spring提供了不同情况下的适配器。

2.1.4.3) initHandlerExceptionResolvers

HanlderExceptionResolver是可以被用户定制的,只要实现该接口,实现resolveException方法并定义为一个bean即可。
resolveException方法返回一个ModelAndView对象,在方法内部对异常的类型进行判断,然后尝试生成对应的ModelAndView对象,如果该方法返回null,则Spring会继续寻找其他实现了HanlderExceptionResolver接口的bean。

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<HandlerExceptionResolver>(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.isDebugEnabled()) {         logger.debug("No HandlerExceptionResolvers found in servlet '" + getServletName() + "': using default");      }   }}
2.1.4.4) initRequestToViewNameTranslator

当Controller方法没有返回一个View或者逻辑视图名称,并且在该方法中没有直接往response输出流里面写数据的时候,Spring就会按照约定好的方式提供一个逻辑视图名称(最简答的情况就是加prefix和suffix)。
这个逻辑视图名称是通过Spring定义的RequestToViewNameTranslator接口的getViewName方法来实现的,用户也可以自定义自己的RequestToViewNameTranslator。
Spring为我们提供了一个默认的实现DefaultRequestToViewNameTranslator。
当Controller方法没有返回一个View或者逻辑视图名称,并且在该方法中没有直接往response输出流里面写数据的时候,Spring就会按照约定好的方式提供一个逻辑视图名称(最简答的情况就是加prefix和suffix)。
这个逻辑视图名称是通过Spring定义的RequestToViewNameTranslator接口的getViewName方法来实现的,用户也可以自定义自己的RequestToViewNameTranslator。
Spring为我们提供了一个默认的实现DefaultRequestToViewNameTranslator。

public static final String REQUEST_TO_VIEW_NAME_TRANSLATOR_BEAN_NAME = "viewNameTranslator";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 +               "]");      }   }}
2.1.4.5) initViewResolvers

当Controller将请求处理结果放到ModelAndView中以后,DispatcherServlet会根据ModelAndView选择合适的视图进行渲染。ViewResolver接口定义了resolveViewName方法,根据viewName创建合适类型的View实现。
可以在Spring的配置文件中定义viewResolver。

private void initViewResolvers(ApplicationContext context) {   this.viewResolvers = null;   if (this.detectAllViewResolvers) {      // Find all ViewResolvers in the ApplicationContext, including ancestor contexts.      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) {      this.viewResolvers = getDefaultStrategies(context, ViewResolver.class);      if (logger.isDebugEnabled()) {         logger.debug("No ViewResolvers found in servlet '" + getServletName() + "': using default");      }   }}
2.1.4.6) initFlashMapManager

flash attributes提供了一个请求存储属性,可供其他请求使用。在使用重定向的时候非常必要。
Spring MVC 有两个主要的抽象来支持 flash attributes。 FlashMap 用于保持 flash attributes 而 FlashMapManager用于存储,检索,管理FlashMap 实例。
Flash attribute 支持默认开启,并不需要显式启用,它永远不会导致HTTP Session的创建。 每一个请求都有一个 “input”FlashMap 具有从上一个请求(如果有的话)传过来的属性和一个 “output” FlashMap 具有将要在后续请求中保存的属性。 这两个 FlashMap 实例都可以通过静态方法RequestContextUtils从Spring MVC的任何位置访问。

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 + "]");      }   }}

处理请求

这里写图片描述

FrameworkServlet.service(入口)

DispatcherServlet(FrameworkServlet的子类)无论是doGet、doPost等方法都会调用processRequest方法处理请求。

FrameworkServlet.processRequest

逻辑:
1)为了保证当前线程的LocaleContext和RequestAttributes可以在当前请求处理完毕后还能恢复,提取当前线程的两个属性
2)根据当前request创建对应的LocaleContext和RequestAttributes,并绑定到当前线程
3)委托给doService方法进一步处理
4)请求处理结束后恢复线程到原始状态
5)请求处理结束后无论成功与否都会发布事件通知

protected final void processRequest(HttpServletRequest request, HttpServletResponse response)      throws ServletException, IOException {   long startTime = System.currentTimeMillis();   Throwable failureCause = null;   LocaleContext previousLocaleContext = LocaleContextHolder.getLocaleContext();   LocaleContext localeContext = buildLocaleContext(request);   RequestAttributes previousAttributes = RequestContextHolder.getRequestAttributes();   ServletRequestAttributes requestAttributes = buildRequestAttributes(request, response, previousAttributes);   WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);   asyncManager.registerCallableInterceptor(FrameworkServlet.class.getName(), new RequestBindingInterceptor());   // 将localeContext和requestAttributes绑定到当前线程   initContextHolders(request, localeContext, requestAttributes);   try {      doService(request, response);   }   catch (ServletException ex) {      failureCause = ex;      throw ex;   }   catch (IOException ex) {      failureCause = ex;      throw ex;   }   catch (Throwable ex) {      failureCause = ex;      throw new NestedServletException("Request processing failed", ex);   }   finally {// 恢复线程到原始状态      resetContextHolders(request, previousLocaleContext, previousAttributes);      if (requestAttributes != null) {         requestAttributes.requestCompleted();      }      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");            }         }      }      // 发布事件通知      publishRequestHandledEvent(request, response, startTime, failureCause);   }}

DispatcherServlet.doService

将已经初始化的功能辅助工具变量设置在request属性中。
主要业务逻辑是在doDispatch方法中处理。

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.   request.setAttribute(WEB_APPLICATION_CONTEXT_ATTRIBUTE, getWebApplicationContext());   request.setAttribute(LOCALE_RESOLVER_ATTRIBUTE, this.localeResolver);   request.setAttribute(THEME_RESOLVER_ATTRIBUTE, this.themeResolver);   request.setAttribute(THEME_SOURCE_ATTRIBUTE, getThemeSource());   FlashMap inputFlashMap = this.flashMapManager.retrieveAndUpdate(request, response);   if (inputFlashMap != null) {      request.setAttribute(INPUT_FLASH_MAP_ATTRIBUTE, Collections.unmodifiableMap(inputFlashMap));   }   request.setAttribute(OUTPUT_FLASH_MAP_ATTRIBUTE, new FlashMap());   request.setAttribute(FLASH_MAP_MANAGER_ATTRIBUTE, this.flashMapManager);   try {      doDispatch(request, response);   }   finally {      if (!WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) {         // Restore the original attribute snapshot, in case of an include.         if (attributesSnapshot != null) {            restoreAttributesAfterInclude(request, attributesSnapshot);         }      }   }}

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 {// 如果request是MultiPartContent类型的,则将其转为MultiPartHttpServletRequest         processedRequest = checkMultipart(request);         multipartRequestParsed = (processedRequest != request);         // 根据request信息寻找对应的Handler         mappedHandler = getHandler(processedRequest);         if (mappedHandler == null || mappedHandler.getHandler() == null) {// 没有找到对应的handler,则通过response反馈错误信息            noHandlerFound(processedRequest, response);            return;         }         // 根据当前的handler寻找对应的HandlerAdapter         HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());         // 如果当前handler支持Last-Modified请求头,则对其进行处理         // 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;            }         }         // 调用拦截器的preHandle方法         if (!mappedHandler.applyPreHandle(processedRequest, response)) {            return;         }         // 调用handler并返回视图         mv = ha.handle(processedRequest, response, mappedHandler.getHandler());         if (asyncManager.isConcurrentHandlingStarted()) {            return;         }         // 转换视图名称(加prefix和suffix)         applyDefaultViewName(processedRequest, mv);// 调用拦截器的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);      }      // 处理handle的结果      processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);   }   catch (Exception ex) {      triggerAfterCompletion(processedRequest, response, mappedHandler, ex);   }   catch (Throwable err) {      triggerAfterCompletion(processedRequest, response, mappedHandler,            new NestedServletException("Handler processing failed", err));   }   finally {      if (asyncManager.isConcurrentHandlingStarted()) {         // Instead of postHandle and afterCompletion         if (mappedHandler != null) {            mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);         }      }      else {         // Clean up any resources used by a multipart request.         if (multipartRequestParsed) {            cleanupMultipart(processedRequest);         }      }   }}

1) checkMultiPart(处理文件上传请求)

protected HttpServletRequest checkMultipart(HttpServletRequest request) throws MultipartException {   if (this.multipartResolver != null && this.multipartResolver.isMultipart(request)) {      if (WebUtils.getNativeRequest(request, MultipartHttpServletRequest.class) != null) {         logger.debug("Request is already a MultipartHttpServletRequest - if not in a forward, " +               "this typically results from an additional MultipartFilter in web.xml");      }      else if (hasMultipartException(request) ) {         logger.debug("Multipart resolution failed for current request before - " +               "skipping re-resolution for undisturbed error rendering");      }      else {         try {            return this.multipartResolver.resolveMultipart(request);         }         catch (MultipartException ex) {            if (request.getAttribute(WebUtils.ERROR_EXCEPTION_ATTRIBUTE) != null) {               logger.debug("Multipart resolution failed for error dispatch", ex);               // Keep processing error dispatch with regular request handle below            }            else {               throw ex;            }         }      }   }   // If not returned before: return original request.   return request;}

MultipartResolver.resolveMultipart

MultipartHttpServletRequest resolveMultipart(HttpServletRequest request) throws MultipartException;

2) getHandler(获取HandlerExecutionChain)

protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {   for (HandlerMapping hm : this.handlerMappings) {      if (logger.isTraceEnabled()) {         logger.trace(               "Testing handler map [" + hm + "] in DispatcherServlet with name '" + getServletName() + "'");      }      HandlerExecutionChain handler = hm.getHandler(request);      if (handler != null) {         return handler;      }   }   return null;}
2.1) AbstractHandlerMapping.getHandler
public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {// 根据request获取对应的handler   Object handler = getHandlerInternal(request);   if (handler == null) {// 如果没有对应的request的handler则使用默认的handler      handler = getDefaultHandler();   }// 没有默认的handler则无法继续处理   if (handler == null) {      return null;   }// 当查找的Controller为String,就意味着返回的是配置的bean名称,需要根据bean名称查找对应的bean   // Bean name or resolved handler?   if (handler instanceof String) {      String handlerName = (String) handler;      handler = getApplicationContext().getBean(handlerName);   }   HandlerExecutionChain executionChain = getHandlerExecutionChain(handler, request);   if (CorsUtils.isCorsRequest(request)) {      CorsConfiguration globalConfig = this.corsConfigSource.getCorsConfiguration(request);      CorsConfiguration handlerConfig = getCorsConfiguration(handler, request);      CorsConfiguration config = (globalConfig != null ? globalConfig.combine(handlerConfig) : handlerConfig);      executionChain = getCorsHandlerExecutionChain(request, executionChain, config);   }   return executionChain;}
2.1.1) AbstractHandlerMethodMapping.getHandlerInternal(加入拦截器)
protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {   String lookupPath = getUrlPathHelper().getLookupPathForRequest(request);   if (logger.isDebugEnabled()) {      logger.debug("Looking up handler method for path " + lookupPath);   }   this.mappingRegistry.acquireReadLock();   try {      HandlerMethod handlerMethod = lookupHandlerMethod(lookupPath, request);      if (logger.isDebugEnabled()) {         if (handlerMethod != null) {            logger.debug("Returning handler method [" + handlerMethod + "]");         }         else {            logger.debug("Did not find handler method for [" + lookupPath + "]");         }      }      return (handlerMethod != null ? handlerMethod.createWithResolvedBean() : null);   }   finally {      this.mappingRegistry.releaseReadLock();   }}
2.1.1.1) lookupHandlerMethod
protected HandlerMethod lookupHandlerMethod(String lookupPath, HttpServletRequest request) throws Exception {   List<Match> matches = new ArrayList<Match>();// 直接匹配   List<T> directPathMatches = this.mappingRegistry.getMappingsByUrl(lookupPath);   if (directPathMatches != null) {      addMatchingMappings(directPathMatches, matches, request);   }   if (matches.isEmpty()) {      // No choice but to go through all mappings...// 加入所有的映射      addMatchingMappings(this.mappingRegistry.getMappings().keySet(), matches, request);   }   if (!matches.isEmpty()) {      Comparator<Match> comparator = new MatchComparator(getMappingComparator(request));// 按匹配程度排序      Collections.sort(matches, comparator);      if (logger.isTraceEnabled()) {         logger.trace("Found " + matches.size() + " matching mapping(s) for [" +               lookupPath + "] : " + matches);      }// 得到最符合的匹配结果      Match bestMatch = matches.get(0);      if (matches.size() > 1) {         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();            throw new IllegalStateException("Ambiguous handler methods mapped for HTTP path '" +                  request.getRequestURL() + "': {" + m1 + ", " + m2 + "}");         }      }      handleMatch(bestMatch.mapping, lookupPath, request);      return bestMatch.handlerMethod;   }   else {      return handleNoMatch(this.mappingRegistry.getMappings().keySet(), lookupPath, request);   }}
2.1.2) getHandlerExecutionChain(加入拦截器)

将handler实例和所有匹配的拦截器封装到HandlerExecutionChain中。

protected HandlerExecutionChain getHandlerExecutionChain(Object handler, HttpServletRequest request) {   HandlerExecutionChain chain = (handler instanceof HandlerExecutionChain ?         (HandlerExecutionChain) handler : new HandlerExecutionChain(handler));   String lookupPath = this.urlPathHelper.getLookupPathForRequest(request);   for (HandlerInterceptor interceptor : this.adaptedInterceptors) {      if (interceptor instanceof MappedInterceptor) {         MappedInterceptor mappedInterceptor = (MappedInterceptor) interceptor;         if (mappedInterceptor.matches(lookupPath, this.pathMatcher)) {            chain.addInterceptor(mappedInterceptor.getInterceptor());         }      }      else {         chain.addInterceptor(interceptor);      }   }   return chain;}

3) noHandlerFound(没有找到HandlerExecutionChain)

protected void noHandlerFound(HttpServletRequest request, HttpServletResponse response) throws Exception {   if (pageNotFoundLogger.isWarnEnabled()) {      pageNotFoundLogger.warn("No mapping found for HTTP request with URI [" + getRequestUri(request) +            "] in DispatcherServlet with name '" + getServletName() + "'");   }// 默认为false   if (this.throwExceptionIfNoHandlerFound) {      throw new NoHandlerFoundException(request.getMethod(), getRequestUri(request),            new ServletServerHttpRequest(request).getHeaders());   }   else {      response.sendError(HttpServletResponse.SC_NOT_FOUND);   }}

4) getHandlerAdapter(根据HandlerExecutionChain获取HandlerAdapter)

protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {   for (HandlerAdapter ha : this.handlerAdapters) {      if (logger.isTraceEnabled()) {         logger.trace("Testing handler adapter [" + ha + "]");      }      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.1) AbstractHandlerMethodAdapter.supports
public final boolean supports(Object handler) {   return (handler instanceof HandlerMethod && supportsInternal((HandlerMethod) handler));}

5) HandlerExecutionChain.applyPreHandle(拦截器preHandle)

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

6) HandlerAdapter.handle(处理请求)

ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception;
6.1) AbstractHandlerMethodAdapter.handle
public final ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)      throws Exception {   return handleInternal(request, response, (HandlerMethod) handler);}
6.1.1) RequestMappingHandlerAdapter.handleInternal
protected ModelAndView handleInternal(HttpServletRequest request,      HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {   ModelAndView mav;   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...      mav = invokeHandlerMethod(request, response, handlerMethod);   }   if (!response.containsHeader(HEADER_CACHE_CONTROL)) {      if (getSessionAttributesHandler(handlerMethod).hasSessionAttributes()) {         applyCacheSeconds(response, this.cacheSecondsForSessionAttributeHandlers);      }      else {         prepareResponse(response);      }   }   return mav;}
6.1.1.1) invokeHandlerMethod
protected ModelAndView invokeHandlerMethod(HttpServletRequest request,      HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {   ServletWebRequest webRequest = new ServletWebRequest(request, response);   try {      WebDataBinderFactory binderFactory = getDataBinderFactory(handlerMethod);      ModelFactory modelFactory = getModelFactory(handlerMethod, binderFactory);      ServletInvocableHandlerMethod invocableMethod = createInvocableHandlerMethod(handlerMethod);      invocableMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers);      invocableMethod.setHandlerMethodReturnValueHandlers(this.returnValueHandlers);      invocableMethod.setDataBinderFactory(binderFactory);      invocableMethod.setParameterNameDiscoverer(this.parameterNameDiscoverer);      ModelAndViewContainer mavContainer = new ModelAndViewContainer();      mavContainer.addAllAttributes(RequestContextUtils.getInputFlashMap(request));      modelFactory.initModel(webRequest, mavContainer, invocableMethod);      mavContainer.setIgnoreDefaultModelOnRedirect(this.ignoreDefaultModelOnRedirect);      AsyncWebRequest asyncWebRequest = WebAsyncUtils.createAsyncWebRequest(request, response);      asyncWebRequest.setTimeout(this.asyncRequestTimeout);      WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);      asyncManager.setTaskExecutor(this.taskExecutor);      asyncManager.setAsyncWebRequest(asyncWebRequest);      asyncManager.registerCallableInterceptors(this.callableInterceptors);      asyncManager.registerDeferredResultInterceptors(this.deferredResultInterceptors);      if (asyncManager.hasConcurrentResult()) {         Object result = asyncManager.getConcurrentResult();         mavContainer = (ModelAndViewContainer) asyncManager.getConcurrentResultContext()[0];         asyncManager.clearConcurrentResult();         if (logger.isDebugEnabled()) {            logger.debug("Found concurrent result value [" + result + "]");         }         invocableMethod = invocableMethod.wrapConcurrentResult(result);      }      invocableMethod.invokeAndHandle(webRequest, mavContainer);      if (asyncManager.isConcurrentHandlingStarted()) {         return null;      }      return getModelAndView(mavContainer, modelFactory, webRequest);   }   finally {      webRequest.requestCompleted();   }}
6.1.1.1.1) ServletInvocableHandlerMethod.invokeAndHandle
public void invokeAndHandle(ServletWebRequest webRequest, ModelAndViewContainer mavContainer,      Object... providedArgs) throws Exception {   Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs);   setResponseStatus(webRequest);   if (returnValue == null) {      if (isRequestNotModified(webRequest) || hasResponseStatus() || mavContainer.isRequestHandled()) {         mavContainer.setRequestHandled(true);         return;      }   }   else if (StringUtils.hasText(this.responseReason)) {      mavContainer.setRequestHandled(true);      return;   }   mavContainer.setRequestHandled(false);   try {      this.returnValueHandlers.handleReturnValue(            returnValue, getReturnValueType(returnValue), mavContainer, webRequest);   }   catch (Exception ex) {      if (logger.isTraceEnabled()) {         logger.trace(getReturnValueHandlingErrorMessage("Error handling return value", returnValue), ex);      }      throw ex;   }}
6.1.1.1.1.1) InvocableHandlerMethod.invokeForRequest
public Object invokeForRequest(NativeWebRequest request, ModelAndViewContainer mavContainer,      Object... providedArgs) throws Exception {   Object[] args = getMethodArgumentValues(request, mavContainer, providedArgs);   if (logger.isTraceEnabled()) {      logger.trace("Invoking '" + ClassUtils.getQualifiedMethodName(getMethod(), getBeanType()) +            "' with arguments " + Arrays.toString(args));   }   Object returnValue = doInvoke(args);   if (logger.isTraceEnabled()) {      logger.trace("Method [" + ClassUtils.getQualifiedMethodName(getMethod(), getBeanType()) +            "] returned [" + returnValue + "]");   }   return returnValue;}
6.1.1.1.1.1.1) InvocableHandlerMethod.doInvoke
protected Object doInvoke(Object... args) throws Exception {   ReflectionUtils.makeAccessible(getBridgedMethod());   try {// Controller中的方法,method.invoke      return getBridgedMethod().invoke(getBean(), args);   }   catch (IllegalArgumentException ex) {      assertTargetBean(getBridgedMethod(), getBean(), args);      String text = (ex.getMessage() != null ? ex.getMessage() : "Illegal argument");      throw new IllegalStateException(getInvocationErrorMessage(text, args), ex);   }   catch (InvocationTargetException ex) {      // Unwrap for HandlerExceptionResolvers ...      Throwable targetException = ex.getTargetException();      if (targetException instanceof RuntimeException) {         throw (RuntimeException) targetException;      }      else if (targetException instanceof Error) {         throw (Error) targetException;      }      else if (targetException instanceof Exception) {         throw (Exception) targetException;      }      else {         String text = getInvocationErrorMessage("Failed to invoke handler method", args);         throw new IllegalStateException(text, targetException);      }   }}
6.1.1.1.1.2) HandlerMethodReturnValueHandler.handleReturnValue

以HandlerMethodReturnValueHandlerComposite为例:

public void handleReturnValue(Object returnValue, MethodParameter returnType,      ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception {   HandlerMethodReturnValueHandler handler = selectHandler(returnValue, returnType);   if (handler == null) {      throw new IllegalArgumentException("Unknown return value type: " + returnType.getParameterType().getName());   }   handler.handleReturnValue(returnValue, returnType, mavContainer, webRequest);}
6.1.1.1.1.2.1) selectHandler
private HandlerMethodReturnValueHandler selectHandler(Object value, MethodParameter returnType) {   boolean isAsyncValue = isAsyncReturnValue(value, returnType);   for (HandlerMethodReturnValueHandler handler : this.returnValueHandlers) {      if (isAsyncValue && !(handler instanceof AsyncHandlerMethodReturnValueHandler)) {         continue;      }      if (handler.supportsReturnType(returnType)) {         return handler;      }   }   return null;}

如果返回值是ModelAndView,那么handler是ModelAndViewMethodReturnValueHandler。
如果返回值是普通的对象(@ResponseBody),那么handler是
RequestResponseBodyMethodProcessor。
实例-MVC属于前者,实例-REST属于后者。

6.1.1.1.1.2.2) handleReturnValue

以RequestResponseBodyMethodProcessor为例:

public void handleReturnValue(Object returnValue, MethodParameter returnType,      ModelAndViewContainer mavContainer, NativeWebRequest webRequest)      throws IOException, HttpMediaTypeNotAcceptableException, HttpMessageNotWritableException {   mavContainer.setRequestHandled(true);   ServletServerHttpRequest inputMessage = createInputMessage(webRequest);   ServletServerHttpResponse outputMessage = createOutputMessage(webRequest);   // Try even with null return value. ResponseBodyAdvice could get involved.   writeWithMessageConverters(returnValue, returnType, inputMessage, outputMessage);}

以ModelAndViewMethodReturnValueHandler为例:

public void handleReturnValue(Object returnValue, MethodParameter returnType,      ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception {   if (returnValue == null) {      mavContainer.setRequestHandled(true);      return;   }   ModelAndView mav = (ModelAndView) returnValue;   if (mav.isReference()) {      String viewName = mav.getViewName();      mavContainer.setViewName(viewName);      if (viewName != null && isRedirectViewName(viewName)) {         mavContainer.setRedirectModelScenario(true);      }   }   else {      View view = mav.getView();      mavContainer.setView(view);      if (view instanceof SmartView) {         if (((SmartView) view).isRedirectView()) {            mavContainer.setRedirectModelScenario(true);         }      }   }   mavContainer.setStatus(mav.getStatus());   mavContainer.addAllAttributes(mav.getModel());}

7) applyDefaultViewName(转换视图名称)

private void applyDefaultViewName(HttpServletRequest request, ModelAndView mv) throws Exception {   if (mv != null && !mv.hasView()) {      mv.setViewName(getDefaultViewName(request));   }}protected String getDefaultViewName(HttpServletRequest request) throws Exception {   return this.viewNameTranslator.getViewName(request);}// DefaultRequestToViewNameTransaltor.getDefaultViewNamepublic String getViewName(HttpServletRequest request) {   String lookupPath = this.urlPathHelper.getLookupPathForRequest(request);   return (this.prefix + transformPath(lookupPath) + this.suffix);}

8) HandlerExecutionChain.applyPostHandle(拦截器postHandle)

void applyPostHandle(HttpServletRequest request, HttpServletResponse response, ModelAndView mv) throws Exception {   HandlerInterceptor[] interceptors = getInterceptors();   if (!ObjectUtils.isEmpty(interceptors)) {      for (int i = interceptors.length - 1; i >= 0; i--) {         HandlerInterceptor interceptor = interceptors[i];         interceptor.postHandle(request, response, this.handler, mv);      }   }}

9) processDispatchResult(处理ModelAndView请求结果)

如果返回的是纯数据(@ResponseBody),mv就是null,该方法基本上是空方法。

private void processDispatchResult(HttpServletRequest request, HttpServletResponse response,      HandlerExecutionChain mappedHandler, ModelAndView mv, Exception exception) throws Exception {   boolean errorView = false;   if (exception != null) {      if (exception instanceof ModelAndViewDefiningException) {         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?// 如果handler处理结果中返回了view,那么需要对页面进行渲染   if (mv != null && !mv.wasCleared()) {      render(mv, request, response);      if (errorView) {         WebUtils.clearErrorRequestAttributes(request);      }   }   else {      if (logger.isDebugEnabled()) {         logger.debug("Null ModelAndView returned to DispatcherServlet with name '" + getServletName() +               "': assuming HandlerAdapter completed request handling");      }   }   if (WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) {      // Concurrent handling started during a forward      return;   }   if (mappedHandler != null) {      mappedHandler.triggerAfterCompletion(request, response, null);   }}
9.1) processHandlerException(处理异常)
protected ModelAndView processHandlerException(HttpServletRequest request, HttpServletResponse response,      Object handler, Exception ex) throws Exception {   // Check registered HandlerExceptionResolvers...   ModelAndView exMv = null;   for (HandlerExceptionResolver handlerExceptionResolver : this.handlerExceptionResolvers) {// 使用handlerExceptionResolver来处理异常      exMv = handlerExceptionResolver.resolveException(request, response, handler, ex);      if (exMv != null) {         break;      }   }   if (exMv != null) {      if (exMv.isEmpty()) {         request.setAttribute(EXCEPTION_ATTRIBUTE, ex);         return null;      }      // We might still need view name translation for a plain error model...      if (!exMv.hasView()) {         exMv.setViewName(getDefaultViewName(request));      }      if (logger.isDebugEnabled()) {         logger.debug("Handler execution resulted in exception - forwarding to resolved error view: " + exMv, ex);      }      WebUtils.exposeErrorRequestAttributes(request, ex, getServletName());      return exMv;   }   throw ex;}
9.2) render(渲染视图)
protected void render(ModelAndView mv, HttpServletRequest request, HttpServletResponse response) throws Exception {   // Determine locale for request and apply it to the response.   Locale locale = this.localeResolver.resolveLocale(request);   response.setLocale(locale);   View view;   if (mv.isReference()) {      // We need to resolve the view name.      view = resolveViewName(mv.getViewName(), mv.getModelInternal(), locale, request);      if (view == null) {         throw new ServletException("Could not resolve view with name '" + mv.getViewName() +               "' in servlet with name '" + getServletName() + "'");      }   }   else {      // No need to lookup: the ModelAndView object contains the actual View object.      view = mv.getView();      if (view == null) {         throw new ServletException("ModelAndView [" + mv + "] neither contains a view name nor a " +               "View object in servlet with name '" + getServletName() + "'");      }   }   // Delegate to the View object for rendering.   if (logger.isDebugEnabled()) {      logger.debug("Rendering view [" + view + "] in DispatcherServlet with name '" + getServletName() + "'");   }   try {      if (mv.getStatus() != null) {         response.setStatus(mv.getStatus().value());      }      view.render(mv.getModelInternal(), request, response);   }   catch (Exception ex) {      if (logger.isDebugEnabled()) {         logger.debug("Error rendering view [" + view + "] in DispatcherServlet with name '" +               getServletName() + "'", ex);      }      throw ex;   }}
9.2.1) resolveViewName(创建视图)
protected View resolveViewName(String viewName, Map<String, Object> model, Locale locale,      HttpServletRequest request) throws Exception {   for (ViewResolver viewResolver : this.viewResolvers) {// 使用viewResolver解析视图名称      View view = viewResolver.resolveViewName(viewName, locale);      if (view != null) {         return view;      }   }   return null;}
9.2.1.1) AbstractCachingViewResolver.resolveViewName
public View resolveViewName(String viewName, Locale locale) throws Exception {   if (!isCache()) {// 不存在缓存的情况下直接创建视图      return createView(viewName, locale);   }   else {// 直接从缓存中获取      Object cacheKey = getCacheKey(viewName, locale);      View view = this.viewAccessCache.get(cacheKey);      if (view == null) {         synchronized (this.viewCreationCache) {            view = this.viewCreationCache.get(cacheKey);            if (view == null) {               // Ask the subclass to create the View object.               view = createView(viewName, locale);               if (view == null && this.cacheUnresolved) {                  view = UNRESOLVED_VIEW;               }               if (view != null) {                  this.viewAccessCache.put(cacheKey, view);                  this.viewCreationCache.put(cacheKey, view);                  if (logger.isTraceEnabled()) {                     logger.trace("Cached view [" + cacheKey + "]");                  }               }            }         }      }      return (view != UNRESOLVED_VIEW ? view : null);   }}
9.2.1.1.1) UrlBasedViewResolver.createView
protected View createView(String viewName, Locale locale) throws Exception {   // If this resolver is not supposed to handle the given view,   // return null to pass on to the next resolver in the chain.// 如果当前解析器不支持当前解析器,如viewName为空等情况   if (!canHandle(viewName, locale)) {      return null;   }// 处理redirect:xx的情况   // Check for special "redirect:" prefix.   if (viewName.startsWith(REDIRECT_URL_PREFIX)) {      String redirectUrl = viewName.substring(REDIRECT_URL_PREFIX.length());      RedirectView view = new RedirectView(redirectUrl, isRedirectContextRelative(), isRedirectHttp10Compatible());      view.setHosts(getRedirectHosts());      return applyLifecycleMethods(viewName, view);   }// 处理forward:xx的情况   // Check for special "forward:" prefix.   if (viewName.startsWith(FORWARD_URL_PREFIX)) {      String forwardUrl = viewName.substring(FORWARD_URL_PREFIX.length());      return new InternalResourceView(forwardUrl);   }   // Else fall back to superclass implementation: calling loadView.   return super.createView(viewName, locale);}

AbstractCachingViewResolver.createView

protected View createView(String viewName, Locale locale) throws Exception {   return loadView(viewName, locale);}

UrlBasedViewResolver.loadView

protected View loadView(String viewName, Locale locale) throws Exception {   AbstractUrlBasedView view = buildView(viewName);   View result = applyLifecycleMethods(viewName, view);   return (view.checkResource(locale) ? result : null);}

UrlBasedViewResolver.buildView

protected AbstractUrlBasedView buildView(String viewName) throws Exception {   AbstractUrlBasedView view = (AbstractUrlBasedView) BeanUtils.instantiateClass(getViewClass());// 添加前缀和后缀   view.setUrl(getPrefix() + viewName + getSuffix());   String contentType = getContentType();   if (contentType != null) {// 设置ContentType      view.setContentType(contentType);   }   view.setRequestContextAttribute(getRequestContextAttribute());   view.setAttributesMap(getAttributesMap());   Boolean exposePathVariables = getExposePathVariables();   if (exposePathVariables != null) {      view.setExposePathVariables(exposePathVariables);   }   Boolean exposeContextBeansAsAttributes = getExposeContextBeansAsAttributes();   if (exposeContextBeansAsAttributes != null) {      view.setExposeContextBeansAsAttributes(exposeContextBeansAsAttributes);   }   String[] exposedContextBeanNames = getExposedContextBeanNames();   if (exposedContextBeanNames != null) {      view.setExposedContextBeanNames(exposedContextBeanNames);   }   return view;}
9.2.2) AbstractView.render(页面跳转)
public void render(Map<String, ?> model, HttpServletRequest request, HttpServletResponse response) throws Exception {   if (logger.isTraceEnabled()) {      logger.trace("Rendering view with name '" + this.beanName + "' with model " + model +         " and static attributes " + this.staticAttributes);   }   // 处理Model   Map<String, Object> mergedModel = createMergedOutputModel(model, request, response);   prepareResponse(request, response);// 处理页面跳转    renderMergedOutputModel(mergedModel, getRequestToExpose(request), response);}
9.2.2.1) AbstractView.createMergedOutputModel(处理Model)
protected Map<String, Object> createMergedOutputModel(Map<String, ?> model, HttpServletRequest request,      HttpServletResponse response) {   @SuppressWarnings("unchecked")   Map<String, Object> pathVars = (this.exposePathVariables ?         (Map<String, Object>) request.getAttribute(View.PATH_VARIABLES) : null);   // Consolidate static and dynamic model attributes.   int size = this.staticAttributes.size();   size += (model != null ? model.size() : 0);   size += (pathVars != null ? pathVars.size() : 0);   Map<String, Object> mergedModel = new LinkedHashMap<String, Object>(size);   mergedModel.putAll(this.staticAttributes);   if (pathVars != null) {      mergedModel.putAll(pathVars);   }   if (model != null) {      mergedModel.putAll(model);   }   // Expose RequestContext?   if (this.requestContextAttribute != null) {      mergedModel.put(this.requestContextAttribute, createRequestContext(request, response, mergedModel));   }   return mergedModel;}
9.2.2.2) renderMergedOutputModel.renderMergedOutputModel(处理页面跳转)
protected void renderMergedOutputModel(      Map<String, Object> model, HttpServletRequest request, HttpServletResponse response) throws Exception {   // 将model中的数据以属性方式设置到request中   // Expose the model object as request attributes.   exposeModelAsRequestAttributes(model, request);   // Expose helpers as request attributes, if any.   exposeHelpers(request);   // Determine the path for the request dispatcher.   String dispatcherPath = prepareForRendering(request, response);   // Obtain a RequestDispatcher for the target resource (typically a JSP).   RequestDispatcher rd = getRequestDispatcher(request, dispatcherPath);   if (rd == null) {      throw new ServletException("Could not get RequestDispatcher for [" + getUrl() +            "]: Check that the corresponding file exists within your web application archive!");   }   // If already included or response already committed, perform include, else forward.   if (useInclude(request, response)) {      response.setContentType(getContentType());      if (logger.isDebugEnabled()) {         logger.debug("Including resource [" + getUrl() + "] in InternalResourceView '" + getBeanName() + "'");      }      rd.include(request, response);   }   else {      // Note: The forwarded resource is supposed to determine the content type itself.      if (logger.isDebugEnabled()) {         logger.debug("Forwarding to resource [" + getUrl() + "] in InternalResourceView '" + getBeanName() + "'");      }      rd.forward(request, response);   }}

运行实例-MVC

getHandler中handlerMappings为
这里写图片描述
hm是0号,它调用getHandler。

HandlerExecutionChain handler = hm.getHandler(request);

该方法中的getHandlerInternal方法这里用到的类是AbstractHandlerMethodMapping。
最终返回的是该handler,类型是HandlerMethod。

这里写图片描述
getHandlerExecutionChain执行完后多了三个interceptor。
这里写图片描述
getHandlerAdapter中的handlerAdapters是
这里写图片描述
遍历时先用到的是RequestMappingHandlerAdapter,调用的supports是AbstractHandlerMethodAdapter。匹配后,返回的adapter是RequestMappingHandlerAdapter类型的
这里写图片描述
然后调用该adapter的handle方法。
handle方法最终会调用Controller的对应方法,然后获取ModelAndView类型返回值的ModelAndViewMethodReturnValueHandler,对modelAndView进行处理。
然后调用applyDefaultViewName方法.
在调用processDispatchResult之前,modelAndView是这样的。
这里写图片描述
然后去调用render方法。
render
->InternalResourceViewResolver.resolveViewName
->UriBasedViewResolver.createView
->UriBasedViewResolver.loadView
->InternalResourceViewResolver.buildView
此时得到的view如下:

这里写图片描述
之后又调用了view的render方法,最终调用了requestDispatcher.forward方法结束整个过程。

运行实例-REST

前面都一样,但是处理请求结果时使用的handler不一样,它使用的是RequestResponseBodyMethodProcessor,将返回值写入输出流。

总结

处理请求流程图

图源网络,侵删。
这里写图片描述

个人总结

Spring MVC底层依赖于Spring的ApplicationContext,又依赖于Web容器,对原生的Servlet进行封装,以Controller的形式提供给用户。
项目初始化发生在两处,一处是项目启动时初始化ServletContext时,另一处是初次访问web时初始化Servlet。
处理请求可以简化为接收请求——处理文件上传——获取Handler——获取HandlerAdapter——拦截器preHandler——处理请求——拦截器postHandle——渲染视图——返回结果。

原创粉丝点击