spring-mvc源码

1 引言

Spring MVC 是 Spring 框架的一部分,专为构建基于 Java 的 Web 应用程序而设计。它遵循 Model-View-Controller(模型-视图-控制器)架构模式,提供了一种结构化的方式来处理用户请求和响应。Spring MVC 提供了对请求处理的高度定制能力,同时保持与 Spring 框架其他模块的良好集成。

在深入了解 Spring MVC 的源码之前,我们需要理解几个关键概念:DispatcherServlet 是 Spring MVC 的前端控制器,负责接收所有的 HTTP 请求并分发给合适的处理器;BeanFactoryApplicationContext 是 Spring 的核心容器,用于管理和创建应用对象(即 Bean);WebApplicationContextApplicationContext 的子接口,专门为 Web 应用提供上下文支持。

2 服务启动过程

2.1 Tomcat 解析配置文件

当使用 Tomcat 作为 Web 容器时,启动流程始于 Tomcat 读取 web 应用的 web.xml 配置文件。这个文件中包含了关于 DispatcherServlet 的配置信息,例如它的初始化参数和映射路径。Tomcat 使用这些信息来创建和初始化 DispatcherServlet 实例。

2.2 创建 DispatcherServlet

DispatcherServlet 被创建后,会调用其 init 方法,这是 Servlet 生命周期的一部分。在这个方法中,DispatcherServlet 将执行一系列的初始化步骤,包括但不限于:

  1. 创建 WebApplicationContext:DispatcherServlet 会尝试从父容器获取一个已存在的 WebApplicationContext,如果找不到,则会创建一个新的。这一步是通过调用 FrameworkServlet.createWebApplicationContext 方法完成的。

  2. 加载 Bean 定义:一旦 WebApplicationContext 被创建或获取,Spring 就会开始加载由开发者定义的所有 Bean。这些 Bean 可以通过 XML 文件或者注解来定义,并且可以位于类路径下的任何位置。

  3. 初始化 Bean:加载完 Bean 定义之后,Spring 开始初始化这些 Bean。这涉及到设置属性值、调用初始化方法以及执行依赖注入等操作。

  4. 注册组件:DispatcherServlet 还会注册一些内部组件,如 HandlerMapping、HandlerAdapter 和 ViewResolver 等,这些组件在处理请求时会被用到。

3 依赖导入

XML 复制代码
<parent>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-parent</artifactId>
  <version>2.1.4.RELEASE</version>
</parent>

<dependencies>
  <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
  </dependency>
  <!-- https://mvnrepository.com/artifact/org.mybatis.spring.boot/mybatis-spring-boot-starter -->
  <dependency>
    <groupId>org.mybatis.spring.boot</groupId>
    <artifactId>mybatis-spring-boot-starter</artifactId>
    <version>2.3.2</version>
  </dependency>

4 启动源码解析

4.1 创建容器

tomcat解析web.xml文件后 会创建一个DispatcherServlet对象 创建好了 会调用父类的init方法

核心类:HttpServletBean 方法:init

java 复制代码
public final void init() throws ServletException {

    // Set bean properties from init parameters.
    PropertyValues pvs = new ServletConfigPropertyValues(getServletConfig(), this.requiredProperties);
    if (!pvs.isEmpty()) {
       try {
          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.
    //1 创建容器对象
    initServletBean();
}

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

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

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

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


protected WebApplicationContext initWebApplicationContext() {
    WebApplicationContext rootContext =
          WebApplicationContextUtils.getWebApplicationContext(getServletContext());
    WebApplicationContext wac = null;

    if (this.webApplicationContext != null) {
       // A context instance was injected at construction time -> use it
       wac = this.webApplicationContext;
       if (wac instanceof ConfigurableWebApplicationContext) {
          ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext) wac;
          if (!cwac.isActive()) {
             // The context has not yet been refreshed -> provide services such as
             // setting the parent context, setting the application context id, etc
             if (cwac.getParent() == null) {
                // The context instance was injected without an explicit parent -> set
                // the root application context (if any; may be null) as the parent
                cwac.setParent(rootContext);
             }
             configureAndRefreshWebApplicationContext(cwac);
          }
       }
    }
    if (wac == null) {
       // No context instance was injected at construction time -> see if one
       // has been registered in the servlet context. If one exists, it is assumed
       // that the parent context (if any) has already been set and that the
       // user has performed any initialization such as setting the context id
       wac = findWebApplicationContext();
    }
    if (wac == null) {
       // No context instance is defined for this servlet -> create a local one
       //在没有配置的情况下 默认为null 需要创建容器
       wac = createWebApplicationContext(rootContext);
    }

    if (!this.refreshEventReceived) {
       // Either the context is not a ConfigurableApplicationContext with refresh
       // support or the context injected at construction time had already been
       // refreshed -> trigger initial onRefresh manually here.
       synchronized (this.onRefreshMonitor) {
          onRefresh(wac);
       }
    }

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

    return wac;
}


protected WebApplicationContext createWebApplicationContext(@Nullable ApplicationContext parent) {
    //1 获取默认的容器对象类型 -- XmlWebApplicationContext
    Class<?> contextClass = getContextClass();
    if (!ConfigurableWebApplicationContext.class.isAssignableFrom(contextClass)) {
       throw new ApplicationContextException(
             "Fatal initialization error in servlet with name '" + getServletName() +
             "': custom WebApplicationContext class [" + contextClass.getName() +
             "] is not of type ConfigurableWebApplicationContext");
    }
    //2 创建容器
    ConfigurableWebApplicationContext wac =
          (ConfigurableWebApplicationContext) BeanUtils.instantiateClass(contextClass);

    wac.setEnvironment(getEnvironment());
    wac.setParent(parent);
    //3 获取spring配置文件路径
    //                        <param-name>contextConfigLocation</param-name>
    //                    <param-value>/WEB-INF/spring.xml</param-value>
    String configLocation = getContextConfigLocation();
    if (configLocation != null) {
       wac.setConfigLocation(configLocation);
    }
    //4 初始化容器
    configureAndRefreshWebApplicationContext(wac);

    return 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 {
          // Generate default id...
          wac.setId(ConfigurableWebApplicationContext.APPLICATION_CONTEXT_ID_PREFIX +
                ObjectUtils.getDisplayString(getServletContext().getContextPath()) + '/' + getServletName());
       }
    }

    wac.setServletContext(getServletContext());
    wac.setServletConfig(getServletConfig());
    wac.setNamespace(getNamespace());
    //1 添加spring容器的监听器 在spring容器刷新后执行
    wac.addApplicationListener(new SourceFilteringListener(wac, new ContextRefreshListener()));

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

    postProcessWebApplicationContext(wac);
    applyInitializers(wac);
    wac.refresh();
}
4.2 spring容器监听事件

核心类:FrameworkServlet 内部类:ContextRefreshListener

java 复制代码
private class ContextRefreshListener implements ApplicationListener<ContextRefreshedEvent> {

    @Override
    public void onApplicationEvent(ContextRefreshedEvent event) {
        //1 监听到容器刷新事件
       FrameworkServlet.this.onApplicationEvent(event);
    }
}

public void onApplicationEvent(ContextRefreshedEvent event) {
    this.refreshEventReceived = true;
    synchronized (this.onRefreshMonitor) {
       onRefresh(event.getApplicationContext());
    }
}

protected void initStrategies(ApplicationContext context) {
    initMultipartResolver(context);
    initLocaleResolver(context);
    initThemeResolver(context);
    //初始化handlerMapping
    initHandlerMappings(context);
    //初始化handlerAdapter
    initHandlerAdapters(context);
    initHandlerExceptionResolvers(context);
    initRequestToViewNameTranslator(context);
    initViewResolvers(context);
    initFlashMapManager(context);
}
4.3 handlerMapping初始化
java 复制代码
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<>(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) {
        //1 获取默认的handlerMappings
       this.handlerMappings = getDefaultStrategies(context, HandlerMapping.class);
       if (logger.isTraceEnabled()) {
          logger.trace("No HandlerMappings declared for servlet '" + getServletName() +
                "': using default strategies from DispatcherServlet.properties");
       }
    }
}


protected <T> List<T> getDefaultStrategies(ApplicationContext context, Class<T> strategyInterface) {
    String key = strategyInterface.getName();
    //1 从DispatcherServlet.properties获取所有默认的handlerMapping
    String value = defaultStrategies.getProperty(key);
    if (value != null) {
       String[] classNames = StringUtils.commaDelimitedListToStringArray(value);
       List<T> strategies = new ArrayList<>(classNames.length);
       for (String className : classNames) {
          try {
             Class<?> clazz = ClassUtils.forName(className, DispatcherServlet.class.getClassLoader());
             //2 创建handlerMapping对象 并存放至spring容器中
             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(
                   "Unresolvable class definition for DispatcherServlet's default strategy class [" +
                   className + "] for interface [" + key + "]", err);
          }
       }
       return strategies;
    }
    else {
       return new LinkedList<>();
    }
}
4.3.1 RequestMappingHandlerMapping初始化

核心方法:afterPropertiesSet

java 复制代码
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());
    //初始化方法
    super.afterPropertiesSet();
}


protected void initHandlerMethods() {
    //1 获取容器中的所有bean对象名称
    for (String beanName : getCandidateBeanNames()) {
       if (!beanName.startsWith(SCOPED_TARGET_NAME_PREFIX)) {
           //2 进一步过滤
          processCandidateBean(beanName);
       }
    }
    handlerMethodsInitialized(getHandlerMethods());
}


protected void processCandidateBean(String beanName) {
    Class<?> beanType = null;
    try {
        //1 获取对象的类型
       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 判断对象上是否存在Controller或者RequestMapping注解 存在才去解析
    if (beanType != null && isHandler(beanType)) {
       detectHandlerMethods(beanName);
    }
}


protected void detectHandlerMethods(Object handler) {
    //1 获取对象类型
    Class<?> handlerType = (handler instanceof String ?
          obtainApplicationContext().getType((String) handler) : handler.getClass());

    if (handlerType != null) {
       Class<?> userType = ClassUtils.getUserClass(handlerType);
       //2 存放方法信息至map。key-->方法  value-->注解信息
       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(formatMappings(userType, methods));
       }
       methods.forEach((method, mapping) -> {
          Method invocableMethod = AopUtils.selectInvocableMethod(method, userType);
          //3 注册方法和注解的信息
          registerHandlerMethod(handler, invocableMethod, mapping);
       });
    }
}


public void register(T mapping, Object handler, Method method) {
    this.readWriteLock.writeLock().lock();
    try {
        //1 封装方法对象
       HandlerMethod handlerMethod = createHandlerMethod(handler, method);
       assertUniqueMethodMapping(handlerMethod, mapping);
       this.mappingLookup.put(mapping, handlerMethod);

       List<String> directUrls = getDirectUrls(mapping);
       for (String url : directUrls) {
           //2 存储路径和注解信息  通过URL找到方法上的注解信息
          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);
       }
        //3 存储注解信息和方法信息  再通过注解可以找到对应的方法
       this.registry.put(mapping, new MappingRegistration<>(mapping, handlerMethod, directUrls, name));
    }
    finally {
       this.readWriteLock.writeLock().unlock();
    }
}
4.4 handlerAdapter初始化

核心类:DispatcherServlet 核心方法:initHandlerAdapters

java 复制代码
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<>(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.isTraceEnabled()) {
          logger.trace("No HandlerAdapters declared for servlet '" + getServletName() +
                "': using default strategies from DispatcherServlet.properties");
       }
    }
}


protected <T> List<T> getDefaultStrategies(ApplicationContext context, Class<T> strategyInterface) {
    String key = strategyInterface.getName();
    //从配置文件中解析默认配置的适配器
    //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
    String value = defaultStrategies.getProperty(key);
    if (value != null) {
       String[] classNames = StringUtils.commaDelimitedListToStringArray(value);
       List<T> strategies = new ArrayList<>(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(
                   "Unresolvable class definition for DispatcherServlet's default strategy class [" +
                   className + "] for interface [" + key + "]", err);
          }
       }
       return strategies;
    }
    else {
       return new LinkedList<>();
    }
}
4.4.1 RequestMappingHandlerAdapter的初始化

核心类:RequestMappingHandlerAdapter 核心方法:afterPropertiesSet

java 复制代码
public void afterPropertiesSet() {
    // Do this first, it may add ResponseBody advice beans
    initControllerAdviceCache();

    if (this.argumentResolvers == null) {
        //1 获取默认的参数解析器
       List<HandlerMethodArgumentResolver> resolvers = getDefaultArgumentResolvers();
       this.argumentResolvers = new HandlerMethodArgumentResolverComposite().addResolvers(resolvers);
    }
    if (this.initBinderArgumentResolvers == null) {
        //2 获取默认的@initbinder解析器
       List<HandlerMethodArgumentResolver> resolvers = getDefaultInitBinderArgumentResolvers();
       this.initBinderArgumentResolvers = new HandlerMethodArgumentResolverComposite().addResolvers(resolvers);
    }
    if (this.returnValueHandlers == null) {
        //3 获取默认的返回值解析器
       List<HandlerMethodReturnValueHandler> handlers = getDefaultReturnValueHandlers();
       this.returnValueHandlers = new HandlerMethodReturnValueHandlerComposite().addHandlers(handlers);
    }
}

5 请求调用源码解析

当客户端发送一个HTTP请求时,请求首先到达DispatcherServletDispatcherServlet是Spring MVC的核心组件,负责协调请求处理的整个过程。

核心方法:doDispatch

java 复制代码
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 通过path获取匹配的handlermapping  
          // Determine handler for the current request.
          mappedHandler = getHandler(processedRequest);
          if (mappedHandler == null) {
             noHandlerFound(processedRequest, response);
             return;
          }

          // Determine handler adapter for the current request.
          //3 通过handlermapping的类型获取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;
             }
          }

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

          // Actually invoke the handler.
          //4 调用真正的方法
          mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

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

          applyDefaultViewName(processedRequest, mv);
          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);
          }
       }
    }
}


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


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);
       if (this.argumentResolvers != null) {
          invocableMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers);
       }
       if (this.returnValueHandlers != null) {
          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();
          LogFormatUtils.traceDebug(logger, traceOn -> {
             String formatted = LogFormatUtils.formatValue(result, !traceOn);
             return "Resume with async result [" + formatted + "]";
          });
          invocableMethod = invocableMethod.wrapConcurrentResult(result);
       }
        //解析参数 调用方法
       invocableMethod.invokeAndHandle(webRequest, mavContainer);
       if (asyncManager.isConcurrentHandlingStarted()) {
          return null;
       }
        //封装返回参数
       return getModelAndView(mavContainer, modelFactory, webRequest);
    }
    finally {
       webRequest.requestCompleted();
    }
}

Spring MVC通过DispatcherServlet作为前端控制器,协调请求处理的整个过程。请求首先被DispatcherServlet接收,然后通过HandlerMapping找到处理请求的处理器,再通过HandlerAdapter调用处理器的方法。处理器方法返回一个ModelAndView对象,DispatcherServlet通过ViewResolver解析视图名称并生成视图,最后视图将模型数据渲染成HTML页面并返回给客户端。

相关推荐
路在脚下@29 分钟前
spring boot的配置文件属性注入到类的静态属性
java·spring boot·sql
啦啦右一30 分钟前
Spring Boot | (一)Spring开发环境构建
spring boot·后端·spring
森屿Serien32 分钟前
Spring Boot常用注解
java·spring boot·后端
苹果醋32 小时前
React源码02 - 基础知识 React API 一览
java·运维·spring boot·mysql·nginx
Hello.Reader2 小时前
深入解析 Apache APISIX
java·apache
菠萝蚊鸭2 小时前
Dhatim FastExcel 读写 Excel 文件
java·excel·fastexcel
旭东怪3 小时前
EasyPoi 使用$fe:模板语法生成Word动态行
java·前端·word
007php0073 小时前
Go语言zero项目部署后启动失败问题分析与解决
java·服务器·网络·python·golang·php·ai编程
∝请叫*我简单先生3 小时前
java如何使用poi-tl在word模板里渲染多张图片
java·后端·poi-tl
ssr——ssss3 小时前
SSM-期末项目 - 基于SSM的宠物信息管理系统
java·ssm