SpringMVC 源码解析 – 请求执行的过程

一、SpringMVC 请求执行的过程

SpringMVC 是一个基于 Spring 框架的 MVC 框架,它简化了 Web 应用程序的开发。采用了前端控制器模式,请求会首先被一个中央控制器 DispatcherServlet 处理,再由其分发到具体的 Controller 进行处理。其中 SpringMVC 的请求执行过程如下图所示:

SpringMVC 源码解析 - 请求执行的过程

执行过程如下:

  1. 1. 用户发送请求至前端控制器DispatcherServlet

  2. 2. DispatcherServlet收到请求调用HandlerMapping处理器映射器

  3. 3. 处理器映射器根据请求url找到具体的处理器,生成处理器对象及处理器拦截器,一并返回给 DispatcherServlet

  4. 4. DispatcherServlet 通过 HandlerAdapter处理器适配器调用处理器

  5. 5. 执行处理器,也就是执行 Controller 中的方法

  6. 6. 处理器执行完成返回ModelAndView

  7. 7. HandlerAdapter将处理器的结果ModelAndView返回给DispatcherServlet

  8. 8. DispatcherServletModelAndView传给ViewReslover视图解析器

  9. 9. ViewReslover解析后返回具体View

  10. 10. DispatcherServletView进行渲染视图,即将模型数据填充至视图中

  11. 11. DispatcherServlet 响应用户

从上面是 SpringMVC 的执行过程中可以看出,其中 DispatcherServlet 占据着核心的位置,就像售票处的工作人员一样,当乘客(浏览器发送的请求)来到售票处时,工作人员(DispatcherServlet)会根据乘客所需要的目的地(请求的处理器)来为他们发放对应的门票(响应结果),下面我们从 DispatcherServlet 入手开始分析 SpringMVC 的源码。

二、SpringMVC 请求执行的过程源码解析

2.1 初始化操作

其中 DispatcherServlet 在 org.springframework.web.servlet 包下,可以看到该类继承了 FrameworkServlet 而 FrameworkServlet 又继承了 HttpServletBeanHttpServletBean 又继承了 HttpServlet ,因此 DispatcherServlet 就是传统 web 项目上的一个 Servlet :

SpringMVC 源码解析 - 请求执行的过程

SpringMVC 源码解析 - 请求执行的过程

SpringMVC 源码解析 - 请求执行的过程

那下面我们就以 Servlet 为切入点进行分析:

首先在 Servlet 中初始化时会触发 init() 方法,而这个方法就在 HttpServletBean 类中:

SpringMVC 源码解析 - 请求执行的过程

在初始化方法中会进行子类的初始化工作,则会触发 FrameworkServlet 中的 initServletBean 方法:

SpringMVC 源码解析 - 请求执行的过程

在 FrameworkServlet 主要调用了 initWebApplicationContext 初始化 WebApplicationContext,在 initWebApplicationContext 方法中会触发子类的 onRefresh 方法进行子类的初始化动作:

SpringMVC 源码解析 - 请求执行的过程

下面就可以来到 DispatcherServlet 中的 onRefresh 方法下:

SpringMVC 源码解析 - 请求执行的过程

使用 initStrategies 方法进行组件的初始化操作,其中 initStrategies 方法的源码如下:

protected void initStrategies(ApplicationContext context) {
    //初始化文件上传解析器
    //默认赋值 org.springframework.web.multipart.support.StandardServletMultipartResolver
    initMultipartResolver(context);
    //初始化国际化语言解析器
    //默认赋值 org.springframework.web.servlet.i18n.AcceptHeaderLocaleResolver
    initLocaleResolver(context);
    //初始化主题解析器
    //默认赋值 org.springframework.web.servlet.theme.FixedThemeResolver
    initThemeResolver(context);
    //初始化处理映射器
    initHandlerMappings(context);
    //初始化处理适配器
    initHandlerAdapters(context);
    //初始化异常处理解析器(@ControllerAdvice)
    //默认赋值 org.springframework.web.servlet.HandlerExceptionResolver接口子类
    //具体解析步骤
    initHandlerExceptionResolvers(context);
    //初始化视图转换器
    //默认赋值 org.springframework.web.servlet.view.DefaultRequestToViewNameTranslator
    initRequestToViewNameTranslator(context);
    //初始化视图解析器
    //默认赋值 org.springframework.web.servlet.ViewResolver接口子类
    initViewResolvers(context);
    //初始化flash管理器
    //默认赋值 org.springframework.web.servlet.support.SessionFlashMapManager
    initFlashMapManager(context);
}

可以看到进行了各种组件的初始化操作,这里我们主要看下 HandlerMappings 和 HandlerAdapters 是如何初始化的,首先看到 initHandlerMappings 方法中:

private void initHandlerMappings(ApplicationContext context) {
    this.handlerMappings = null;
    // 从上下文中获取 handlerMapping,分为按类型获取,以及按名称获取
    // 是否检测所有的 handlerMapping , 默认为 true , 通过类型的方式从容器中获取 handlerMapping
    if (this.detectAllHandlerMappings) {
        // 获取全部的 handlerMapping
        Map<String, HandlerMapping> matchingBeans =
                BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerMapping.class, true, false);
        //handlerMapping 结果集不为空
        if (!matchingBeans.isEmpty()) {
            // 将映射器存入 handlerMappings 容器中
            this.handlerMappings = new ArrayList<>(matchingBeans.values());
            // 根据order配置对handlerMapping进行排序, 所有的HandlerMapping都实现了Ordered接口
            AnnotationAwareOrderComparator.sort(this.handlerMappings);
        }
    } else {
        try {
            // 根据名称获取 handlerMapping
            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.
    // 如果不存在 handlerMapping
    if (this.handlerMappings == null) {
        // 使用默认,默认策略不改动的情况下为: BeanNameUrl, RequestMapping, RouterFunction
        this.handlerMappings = getDefaultStrategies(context, HandlerMapping.class);
        if (logger.isTraceEnabled()) {
            logger.trace("No HandlerMappings declared for servlet '" + getServletName() +
                    "': using default strategies from DispatcherServlet.properties");
        }
    }
    // 遍历全部的 handlerMapping
    for (HandlerMapping mapping : this.handlerMappings) {
        // 存在 handlerMapping 使用路径解析模式则赋值 parseRequestPath 为 true
        if (mapping.usesPathPatterns()) {
            this.parseRequestPath = true;
            break;
        }
    }
}

这里会去 Spring 容器中获取 handlerMapping ,如果不存在则会通过 getDefaultStrategies 方法获取一个默认的 handlerMappinggetDefaultStrategies 方法的源码如下:

protected <T> List<T> getDefaultStrategies(ApplicationContext context, Class<T> strategyInterface) {
    if (defaultStrategies == null) {
        try {
            // Load default strategy implementations from properties file.
            // This is currently strictly internal and not meant to be customized
            // by application developers.
            //加载 DispatcherServlet 同级包中的 DispatcherServlet.properties
            ClassPathResource resource = new ClassPathResource(DEFAULT_STRATEGIES_PATH, DispatcherServlet.class);
            defaultStrategies = PropertiesLoaderUtils.loadProperties(resource);
        } catch (IOException ex) {
            throw new IllegalStateException("Could not load '" + DEFAULT_STRATEGIES_PATH + "': " + ex.getMessage());
        }
    }
    //获取接口名作为key
    String key = strategyInterface.getName();
    //在 DispatcherServlet.properties 中获取对应的 value 值
    String value = defaultStrategies.getProperty(key);
    // 如果存在 value
    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 Collections.emptyList();
    }
}

下面再看 initHandlerAdapters 方法,初始化处理适配器:

private void initHandlerAdapters(ApplicationContext context) {
    this.handlerAdapters = null;
    // 是否检查所有的 HandlerAdapter ,默认为 true
    if (this.detectAllHandlerAdapters) {
        // Find all HandlerAdapters in the ApplicationContext, including ancestor contexts.
        // 根据类型获取全部的 HandlerAdapter
        Map<String, HandlerAdapter> matchingBeans =
                BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerAdapter.class, true, false);
        // 如果结果集不为空
        if (!matchingBeans.isEmpty()) {
            // 将 HandlerAdapter 记入 handlerAdapters 容器中
            this.handlerAdapters = new ArrayList<>(matchingBeans.values());
            // We keep HandlerAdapters in sorted order.
            // 排序
            AnnotationAwareOrderComparator.sort(this.handlerAdapters);
        }
    } else {
        try {
            // 根据名称获取 HandlerAdapter
            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.
    // 如果不存在 HandlerAdapter
    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");
        }
    }
}

在该方法中,同样也是会先去 Spring 容器中获取,如果获取不到,则同样使用 getDefaultStrategies 创建一个默认的 HandlerAdapter

2.2 请求执行操作

在 Servlet 中请求进来后,会根据请求类型的不同触发相应的方法,比如 doGet() 或 doPost() 方法,这些方法在 FrameworkServlet 中:

SpringMVC 源码解析 - 请求执行的过程

可以看到,都调用了当前类的 processRequest 方法,在该方法中,则主要触发了子类的 doService 方法:

SpringMVC 源码解析 - 请求执行的过程

下面主要来看 DispatcherServlet 中的 doService 方法:

protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {
    // 记录请求日志
    logRequest(request);

    // 保存 request 属性,用于请求执行完属性清理后的属性恢复
    Map<String, Object> attributesSnapshot = null;
    // 当为 include 请求时,对 request 的 Attribute 做快照备份
    if (WebUtils.isIncludeRequest(request)) {
        attributesSnapshot = new HashMap<>();
        Enumeration<?> attrNames = request.getAttributeNames();
        while (attrNames.hasMoreElements()) {
            String attrName = (String) attrNames.nextElement();
            // 判断 是否开启属性清理功能  或者 属性名的前缀为 org.springframework.web.servlet
            if (this.cleanupAfterInclude || attrName.startsWith(DEFAULT_STRATEGIES_PREFIX)) {
                //放入缓存中
                attributesSnapshot.put(attrName, request.getAttribute(attrName));
            }
        }
    }

    // 设置相关资源属性 用于后续请求过程的处理
    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());

    // 如果 flashMapManager 不为空
    if (this.flashMapManager != null) {
        // 用于在 redirect 记录参数信息
        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());
        // 记录 flushManager
        request.setAttribute(FLASH_MAP_MANAGER_ATTRIBUTE, this.flashMapManager);
    }

    // 是否进行路径解析(默认不进行)
    RequestPath requestPath = null;
    if (this.parseRequestPath && !ServletRequestPathUtils.hasParsedRequestPath(request)) {
        requestPath = ServletRequestPathUtils.parseAndCache(request);
    }

    try {
        // 主要处理逻辑
        doDispatch(request, response);
    } finally {
        if (!WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) {
            // Restore the original attribute snapshot, in case of an include.
            // request属性恢复
            if (attributesSnapshot != null) {
                restoreAttributesAfterInclude(request, attributesSnapshot);
            }
        }
        // 原 request 请求路径恢复
        if (requestPath != null) {
            ServletRequestPathUtils.clearParsedRequestPath(request);
        }
    }
}

该方法中主要则进行了一些属性的记录,主要逻辑则调用了 doDispatch 方法,下面进到 doDispatch 方法中:

protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
    //请求对象
    HttpServletRequest processedRequest = request;
    //处理请求的处理器链(包含 handler 和对应的 Interceptor)
    HandlerExecutionChain mappedHandler = null;
    boolean multipartRequestParsed = false;

    //获取异步处理管理器,servlet3.0后支持异步处理
    WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);

    try {
        //  Model 和 View 的容器
        ModelAndView mv = null;
        // 处理请求 过程中,抛出的异常
        Exception dispatchException = null;

        try {
            // 检查是不是上传文件
            // 检查请求头中 Content-Type 属性是否为 multipart/form-data or multipart/ 开头
            // 如果是文件上传则构建一个 StandardMultipartHttpServletRequest 对象
            processedRequest = checkMultipart(request);
            multipartRequestParsed = (processedRequest != request);

            // Determine handler for the current request.
            // 根据 request 找到 handler
            mappedHandler = getHandler(processedRequest);
            if (mappedHandler == null) {
                // 找不到,报404错误
                noHandlerFound(processedRequest, response);
                return;
            }

            // Determine handler adapter for the current request.
            // 根据 handler 找到 handlerAdapter 适配器
            HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());

            // Process last-modified header, if supported by the handler.
            // 获取请求方式
            String method = request.getMethod();
            // 处理 GET,HEAD 请求的  Last-Modified
            // 浏览器第一次跟服务器请求资源时(GET,HEAD请求),服务器的响应头会包含 Last-Modified属性
            boolean isGet = "GET".equals(method);
            if (isGet || "HEAD".equals(method)) {
                //获取最后修改时间
                long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
                //调用checkNotModified方法验证 http 请求头中的“If-Modified-Since”的时间进行对比,判断页面是否更新过。
                //如果有更新才执行具体的Controller, 没有更新则响应 304 状态码信息(HTTP 304: Not Modified )
                if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
                    return;
                }
            }

            // 调用拦截器的preHandle方法,若返回false,处理结束
            if (!mappedHandler.applyPreHandle(processedRequest, response)) {
                return;
            }

            // Actually invoke the handler.
            // 调用 handler 处理请求,获取 ModelAndView 对象
            // controller 便是在此处执行的
            mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

            // 如果异步正在执行,直接返回
            if (asyncManager.isConcurrentHandlingStarted()) {
                return;
            }

            // 当 view 为空时, 比如 Handler 返回值 为 void, 则根据 request 设置一个默认 view
            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);
        }
        // 处理上面处理之后的结果 (包括 处理异常,渲染页面,发出完成通知触发  Interceptor 的 afterCompletion)
        processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
    } catch (Exception ex) {
        // 调用拦截器的 afterCompletion 方法
        triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
    } catch (Throwable err) {
        triggerAfterCompletion(processedRequest, response, mappedHandler,
                new NestedServletException("Handler processing failed", err));
    } finally {
        //对于异步处理的情况,调用异步处理的拦截器 AsyncHandlerInterceptor 的 afterConcurrentHandlingStarted 方法
        if (asyncManager.isConcurrentHandlingStarted()) {
            // Instead of postHandle and afterCompletion
            if (mappedHandler != null) {
                mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
            }
        } else {
            // Clean up any resources used by a multipart request.
            // 对于multipart的请求,清理资源,比如文件上传的请求,
            // 在上传的过程中文件会被保存到临时文件中,这里就会对这些文件继续清理
            if (multipartRequestParsed) {
                cleanupMultipart(processedRequest);
            }
        }
    }
}

从该方法的执行逻辑,是不是和文章开头写的执行过程非常相似,没错,doDispatch 方法就是整个 SpringMVC 的核心逻辑方法,下面我们主要就该方法进行解析:

2.3 getHandler

在这里首先使用 getHandler方法找到相应的 handler 也就是 Controller,下面进入到该方法中看下逻辑:

protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
    if (this.handlerMappings != null) {
        // 遍历 HandlerMapping 默认由优先级最高的 requestMappingHandlerMapping 来进行处理
        for (HandlerMapping mapping : this.handlerMappings) {
            //获取处理器
            HandlerExecutionChain handler = mapping.getHandler(request);
            if (handler != null) {
                return handler;
            }
        }
    }
    return null;
}

遍历了所有的处理器映射器HandlerMapping,调用他们的getHandler方法得到能够处理当前请求的HandlerExecutionChain对象, 这个对象中包含了 3 个信息:

  • • handler:请求处理器,通常就是我们自定义的 controller 对象及方法

  • • interceptorList:拦截器,当前请求匹配到的拦截器列表

  • • interceptorIndex:拦截器索引,用来记录执行到第几个拦截器了

下面进到 mapping.getHandler 方法下,看是如何获取的,这里则主要触发的 AbstractHandlerMapping 类下的 getHandler 方法:

public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
    // 模板方法,留给子类实现
    Object handler = getHandlerInternal(request);
    if (handler == null) {
        //handler为空获取默认的处理器 默认的 handler 也为 null
        handler = getDefaultHandler();
    }
    if (handler == null) {
        return null;
    }
    // handler 如果是字符串对象,则通过 Spring 容器尝试获取 Handler 实例
    if (handler instanceof String) {
        String handlerName = (String) handler;
        // 获取 bean 实例
        handler = obtainApplicationContext().getBean(handlerName);
    }

    //获取 HandlerExecutionChain 对象 ,包含 handler 和对应的 Interceptor
    HandlerExecutionChain executionChain = getHandlerExecutionChain(handler, request);

    if (logger.isTraceEnabled()) {
        logger.trace("Mapped to " + handler);
    }
    else if (logger.isDebugEnabled() && !request.getDispatcherType().equals(DispatcherType.ASYNC)) {
        logger.debug("Mapped to " + executionChain.getHandler());
    }
    //跨域处理
    if (hasCorsConfigurationSource(handler) || CorsUtils.isPreFlightRequest(request)) {
        // cors 的检查请求
        CorsConfiguration config = getCorsConfiguration(handler, request);
        if (getCorsConfigurationSource() != null) {
            CorsConfiguration globalConfig = getCorsConfigurationSource().getCorsConfiguration(request);
            config = (globalConfig != null ? globalConfig.combine(config) : config);
        }
        if (config != null) {
            config.validateAllowCredentials();
        }
        executionChain = getCorsHandlerExecutionChain(request, executionChain, config);
    }

    return executionChain;
}

在该方法中,首先则调用子类的 getHandlerInternal 方法获取到 handler 其实是 HandlerMethod 对象,最后生成了一个 HandlerExecutionChain 封装对象,这里看下 getHandlerInternal 方法的逻辑,该方法在 AbstractHandlerMethodMapping 类下:

protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {
    // 获取请求路径
    String lookupPath = initLookupPath(request);
    // 映射存储器,尝试获取锁
    this.mappingRegistry.acquireReadLock();
    try {
        // 通过路径和请求找到 HandlerMethod
        HandlerMethod handlerMethod = lookupHandlerMethod(lookupPath, request);
        // 如果找到则创建一个新的 HandlerMethod 返回
        return (handlerMethod != null ? handlerMethod.createWithResolvedBean() : null);
    }
    finally {
        // 放行锁
        this.mappingRegistry.releaseReadLock();
    }
}

首先会拿到请求路径,然后通过 lookupHandlerMethod 方法根据路径找到相应的 HandlerMethod ,下面是该方法的逻辑:

protected HandlerMethod lookupHandlerMethod(String lookupPath, HttpServletRequest request) throws Exception {
    List<Match> matches = new ArrayList<>();
    // 根据 loopuPath 获取对应 RequestInfoMapping 对象集合
    List<T> directPathMatches = this.mappingRegistry.getMappingsByDirectPath(lookupPath);
    if (directPathMatches != null) {
        // 将找到的 RequestInfoMapping 添加到容器缓存
        addMatchingMappings(directPathMatches, matches, request);
    }
    if (matches.isEmpty()) {
        // 如果没找到,则将所有匹配条件的添加到容器缓存
        addMatchingMappings(this.mappingRegistry.getRegistrations().keySet(), matches, request);
    }
    if (!matches.isEmpty()) {
        // 获取容器中的第一个
        Match bestMatch = matches.get(0);
        if (matches.size() > 1) {
            // 数量大于1的话进行排序后取第一个 HandlerMethod 包装类,请求条件数量多的优先
            Comparator<Match> comparator = new MatchComparator(getMappingComparator(request));
            matches.sort(comparator);
            bestMatch = matches.get(0);
            if (logger.isTraceEnabled()) {
                logger.trace(matches.size() + " matching mappings: " + matches);
            }
            if (CorsUtils.isPreFlightRequest(request)) {
                return PREFLIGHT_AMBIGUOUS_MATCH;
            }
            // 取第二个最优匹配
            Match secondBestMatch = matches.get(1);
            // 前两个最优匹配一致,则会抛出异常
            if (comparator.compare(bestMatch, secondBestMatch) == 0) {
                Method m1 = bestMatch.handlerMethod.getMethod();
                Method m2 = secondBestMatch.handlerMethod.getMethod();
                String uri = request.getRequestURI();
                throw new IllegalStateException(
                        "Ambiguous handler methods mapped for '" + uri + "': {" + m1 + ", " + m2 + "}");
            }
        }
        //设置 HandlerMethod 的 request 属性
        request.setAttribute(BEST_MATCHING_HANDLER_ATTRIBUTE, bestMatch.handlerMethod);
        // 路径变量处理
        handleMatch(bestMatch.mapping, lookupPath, request);
        return bestMatch.handlerMethod;
    }
    else {
        return handleNoMatch(this.mappingRegistry.getRegistrations().keySet(), lookupPath, request);
    }
}

主要还是根据 loopuPath 获取对应 RequestInfoMapping 对象集合。

下面再回到 DispatcherServlet 中,获取到 HandlerExecutionChain 对象后,如果没有找到相应的 handler ,则无该接口即返回 404 :

SpringMVC 源码解析 - 请求执行的过程

接着则是使用 getHandlerAdapter 根据 handler 找到 handlerAdapter 适配器。

SpringMVC 源码解析 - 请求执行的过程

2.4 getHandlerAdapter

进入到 getHandlerAdapter 方法中:

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

这里遍历所有的 handlerAdapter 通过 adapter.supports 方法判断是否支持,如果支持则直接返回,最后如果都不支持的话则抛出异常,下面看下 adapter.supports 方法,在 AbstractHandlerMethodAdapter 类下:

public final boolean supports(Object handler) {
    //  handler 必须是 HandlerMethod 的子类
    return (handler instanceof HandlerMethod && supportsInternal((HandlerMethod) handler));
}

判断父类是HandlerMethod类型就可以了,其中 supportsInternal 主要触发的是 RequestMappingHandlerAdapter 类的 supportsInternal 方法,在该类中直接返回 true

SpringMVC 源码解析 - 请求执行的过程

下面再回到 DispatcherServlet 中,获取到 HandlerAdapter 后,接着向下执行会根据请求方式处理 Last-Modified属性:

SpringMVC 源码解析 - 请求执行的过程

再向下执行则会调用拦截器的preHandle方法:

SpringMVC 源码解析 - 请求执行的过程

2.5 applyPreHandle

下面进入到 mappedHandler.applyPreHandle 方法中:

boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception {
    for (int i = 0; i < this.interceptorList.size(); i++) {
        HandlerInterceptor interceptor = this.interceptorList.get(i);
        // 拦截器前置处理
        if (!interceptor.preHandle(request, response, this.handler)) {
            // 前置处理返回 false 则执行拦截器中的 afterCompletion 方法
            triggerAfterCompletion(request, response, null);
            return false;
        }
        this.interceptorIndex = i;
    }
    return true;
}

这里直接获取到前面拿到的所有的拦截器,并触发 preHandle 方法,如果返回了 false,则表示在拦截器中就截断了,这里直接调用拦截器的 afterCompletion 方法。

再回到 DispatcherServlet 中,如果拦截器中的 preHandle 方法返回了 false ,那这里也没必要向下走了,直接 return 结束执行。

再向下执行的话,则来到了 ha.handle 中,这里则主要调用 handler 处理请求,获取 ModelAndView 对象,Controller 便是在此处执行的:

SpringMVC 源码解析 - 请求执行的过程

2.6 handle

该方法主要触发的是 AbstractHandlerMethodAdapter 类下的 handle 方法:

SpringMVC 源码解析 - 请求执行的过程

这里又主要调用了子类的 handleInternal 方法,其实是 RequestMappingHandlerAdapter 类的 handleInternal 方法:

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

    // 基于控制器的方法执行时,不论返回值是多少,都会被处理成 ModelAndView
    ModelAndView mav;
    //检查请求中所支持的方法和是否需要session
    checkRequest(request);

    // Execute invokeHandlerMethod in synchronized block if required.
    // 是否需要基于session来执行加锁执行
    if (this.synchronizeOnSession) {
        HttpSession session = request.getSession(false);
        if (session != null) {
            //获取锁
            Object mutex = WebUtils.getSessionMutex(session);
            // 上锁
            synchronized (mutex) {
                // 同步执行
                mav = invokeHandlerMethod(request, response, handlerMethod);
            }
        }
        else {
            // No HttpSession available -> no mutex necessary
            // 没有session,则直接运行
            mav = invokeHandlerMethod(request, response, handlerMethod);
        }
    }
    else {
        // No synchronization on session demanded at all...
        // 没有同步要求,也是直接运行
        mav = invokeHandlerMethod(request, response, handlerMethod);
    }

    // 如果有 @SessionAttribute 注解,则阻止使用缓存
    if (!response.containsHeader(HEADER_CACHE_CONTROL)) {
        // 检查处理器类,是否有 @SessionAttributes 注解(检查注释里面的 name 和 types参数)
        if (getSessionAttributesHandler(handlerMethod).hasSessionAttributes()) {
            applyCacheSeconds(response, this.cacheSecondsForSessionAttributeHandlers);
        }
        else {
            // 给response设置缓存过期时间
            prepareResponse(response);
        }
    }
    return mav;
}

从该方法的逻辑中可以看出,实际执行逻辑又调用了 invokeHandlerMethod 方法,下面再来到该方法下:

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

    // 构建一个ServletWebRequest对象
    ServletWebRequest webRequest = new ServletWebRequest(request, response);
    try {
        // 参数绑定,主要功能就是实现参数,跟 String 之间的类型转换
        WebDataBinderFactory binderFactory = getDataBinderFactory(handlerMethod);
        // 获取ModelFactory,主要用于在处理器具体处理之前,对 Model 进行初始化,处理完请求后,对 Model 参数进行更新
        ModelFactory modelFactory = getModelFactory(handlerMethod, binderFactory);
        // ServletInvocableHandlerMethod 继承自 HandlerMethod,主要用于参数绑定,处理请求  以及 返回值处理
        ServletInvocableHandlerMethod invocableMethod = createInvocableHandlerMethod(handlerMethod);
        //如果参数解析器不为空
        if (this.argumentResolvers != null) {
            // 设置参数解析器
            invocableMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers);
        }
        // 如果返回值处理器不为空
        if (this.returnValueHandlers != null) {
            // 设置返回值处理器
            invocableMethod.setHandlerMethodReturnValueHandlers(this.returnValueHandlers);
        }
        // 设置参数绑定工厂
        invocableMethod.setDataBinderFactory(binderFactory);
        // 设置 parameterNameDiscoverer
        invocableMethod.setParameterNameDiscoverer(this.parameterNameDiscoverer);

        // 创建一个 ModelAndViewContainer,用于保存 Model 和 View
        ModelAndViewContainer mavContainer = new ModelAndViewContainer();
        // 将 FlashMap 中的数据,添加到Model
        mavContainer.addAllAttributes(RequestContextUtils.getInputFlashMap(request));
        // 使用modelFactory 将 sessionAttributes 和 注释了 @ModelAttribute的方法的参数设置到 Model
        modelFactory.initModel(webRequest, mavContainer, invocableMethod);
        // 对 ignoreDefaultModelOnRedirect进行设置
        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;
        }
        //返回 ModelAndView
        return getModelAndView(mavContainer, modelFactory, webRequest);
    }
    finally {
        webRequest.requestCompleted();
    }
}

该方法则是具体执行请求的处理,首先通过 getDataBinderFactory 方法进行参数的绑定,下面看下该方法的逻辑:

private WebDataBinderFactory getDataBinderFactory(HandlerMethod handlerMethod) throws Exception {
    Class<?> handlerType = handlerMethod.getBeanType();
    // 检查当前 Handler中的InitBinger方法 是否已经再缓存中
    Set<Method> methods = this.initBinderCache.get(handlerType);
    // 如果没有,则查找 并设置到缓存中
    if (methods == null) {
        methods = MethodIntrospector.selectMethods(handlerType, INIT_BINDER_METHODS);
        this.initBinderCache.put(handlerType, methods);
    }
    // 定义保存 InitBinder方法的临时变量
    List<InvocableHandlerMethod> initBinderMethods = new ArrayList<>();
    // Global methods first
    // 将所有符合条件的全局 InitBinder方法添加到 initBinderMethods
    this.initBinderAdviceCache.forEach((controllerAdviceBean, methodSet) -> {
        if (controllerAdviceBean.isApplicableToBeanType(handlerType)) {
            Object bean = controllerAdviceBean.resolveBean();
            for (Method method : methodSet) {
                initBinderMethods.add(createInitBinderMethod(bean, method));
            }
        }
    });
    // 将当前 Handler中的  initBinder方法添加到 initBinderMethods中
    for (Method method : methods) {
        Object bean = handlerMethod.getBean();
        initBinderMethods.add(createInitBinderMethod(bean, method));
    }
    // 创建 DataBinderFactory并返回
    return createDataBinderFactory(initBinderMethods);
}

再回到 invokeHandlerMethod 方法中,继续下面看,会创建一个 ModelAndViewContainer对象,用于保存 Model 和 View,后面该对象则给到了 invokeAndHandle 方法,做执行并处理请求的逻辑,下面进入到 invokeAndHandle 方法:

public void invokeAndHandle(ServletWebRequest webRequest, ModelAndViewContainer mavContainer,
        Object... providedArgs)
 throws Exception {

    // 使用父类的方法,执行请求
    Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs);
    // 处理 @ResponseStatus 注解
    setResponseStatus(webRequest);

    // 处理返回值
    if (returnValue == null) {
        // 判断如果 request 的 notModified为真 或者 @ResponseStatus 存在,或者 mavContainer 的 requestandled 为 true
        if (isRequestNotModified(webRequest) || getResponseStatus() != null || mavContainer.isRequestHandled()) {
            //如果是 not modified 类型请求则进行缓存失效
            disableContentCachingIfNecessary(webRequest);
            //请求设置被完整处理
            mavContainer.setRequestHandled(true);
            return;
        }
    }
    // 如果 returnValue 不为空,并且 @ResponseStatus 注解里面有 reason,则也设置为请求已经处理,并返回
    else if (StringUtils.hasText(getResponseStatusReason())) {
        //请求设置被完整处理
        mavContainer.setRequestHandled(true);
        return;
    }

    //请求设置被完整处理
    mavContainer.setRequestHandled(false);
    Assert.state(this.returnValueHandlers != null, "No return value handlers");
    try {
        // 处理返回值
        this.returnValueHandlers.handleReturnValue(
                returnValue, getReturnValueType(returnValue), mavContainer, webRequest);
    }
    catch (Exception ex) {
        if (logger.isTraceEnabled()) {
            logger.trace(formatErrorForReturnValue(returnValue), ex);
        }
        throw ex;
    }
}

在该方法中实际的执行请求则又调用了父类的的 invokeForRequest 方法,就是 InvocableHandlerMethod 类下的 invokeForRequest 方法:

public Object invokeForRequest(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer,
        Object... providedArgs)
 throws Exception {

    // 解析出方法所需要的参数
    Object[] args = getMethodArgumentValues(request, mavContainer, providedArgs);
    if (logger.isTraceEnabled()) {
        logger.trace("Arguments: " + Arrays.toString(args));
    }
    //通过反射执行对应处理器方法
    return doInvoke(args);
}

这里通过 getMethodArgumentValues 方法解析出方法所需要的参数:

protected Object[] getMethodArgumentValues(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer,
        Object... providedArgs) throws Exception {

    // 获取方法的参数,在HandlerMethod中
    MethodParameter[] parameters = getMethodParameters();
    // 如果为空,则返回空数组
    if (ObjectUtils.isEmpty(parameters)) {
        return EMPTY_ARGS;
    }

    // 用于保存解析出参数的值
    Object[] args = new Object[parameters.length];
    for (int i = 0; i < parameters.length; i++) {
        MethodParameter parameter = parameters[i];
        // 给parameter设置参数名解析器
        parameter.initParameterNameDiscovery(this.parameterNameDiscoverer);
        // 如果相应类型的参数 已经在proivdedArgs中提供了,则直接设置到 parameter
        args[i] = findProvidedArgument(parameter, providedArgs);
        if (args[i] != null) {
            continue;
        }
        // 如果不支持参数则抛出异常
        if (!this.resolvers.supportsParameter(parameter)) {
            throw new IllegalStateException(formatArgumentError(parameter, "No suitable resolver"));
        }
        try {
            //  参数解析
            args[i] = this.resolvers.resolveArgument(parameter, mavContainer, request, this.dataBinderFactory);
        }
        catch (Exception ex) {
            // Leave stack trace for later, exception may actually be resolved and handled...
            if (logger.isDebugEnabled()) {
                String exMsg = ex.getMessage();
                if (exMsg != null && !exMsg.contains(parameter.getExecutable().toGenericString())) {
                    logger.debug(formatArgumentError(parameter, exMsg));
                }
            }
            throw ex;
        }
    }
    return args;
}

回到 invokeForRequest 方法,继续向下,则采用反射 invoke 方式执行方法,可以看下 doInvoke 的逻辑:

protected Object doInvoke(Object... args) throws Exception {
    // 先使用反射将之强制变为可用
    ReflectionUtils.makeAccessible(getBridgedMethod());
    try {
        // 通过反射,调用bean的对应方法
        return getBridgedMethod().invoke(getBean(), args);
    }
    catch (IllegalArgumentException ex) {
        assertTargetBean(getBridgedMethod(), getBean(), args);
        String text = (ex.getMessage() != null ? ex.getMessage() : "Illegal argument");
        throw new IllegalStateException(formatInvokeError(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 {
            throw new IllegalStateException(formatInvokeError("Invocation failure", args), targetException);
        }
    }
}

到这已经通过反射执行了 Controller 中的具体方法。

下面再回到 invokeAndHandle 方法下,这里将实际handler方法的返回,最后通过 returnValueHandlers.handleReturnValue 执行返回值的处理:

SpringMVC 源码解析 - 请求执行的过程

进入 returnValueHandlers.handleReturnValue 方法下:

public void handleReturnValue(@Nullable 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);
}

这里又主要触发了 handler.handleReturnValue 方法,主要调用的子类的实现方法,这里的实现比较多:

SpringMVC 源码解析 - 请求执行的过程

主要看下 ViewNameMethodReturnValueHandler 解析器下的 handleReturnValue 方法,这个使用的比较多:

public void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType,
        ModelAndViewContainer mavContainer, NativeWebRequest webRequest)
 throws Exception {

    if (returnValue instanceof CharSequence) {
        String viewName = returnValue.toString();
        // 如果返回值为String,则将其设置到 mavContainer 的 view 中
        mavContainer.setViewName(viewName);
        if (isRedirectViewName(viewName)) {
            mavContainer.setRedirectModelScenario(true);
        }
    }
    else if (returnValue != null) {
        // should not happen
        throw new UnsupportedOperationException("Unexpected return type: " +
                returnType.getParameterType().getName() + " in method: " + returnType.getMethod());
    }
    // void 返回值,什么也不处理
}

这里会将结果值填充至 ModelAndViewContainer 中的 viewName 属性中。

下面再回到 invokeHandlerMethod 方法中,通过 invocableMethod.invokeAndHandle 已经将返回值放入到 mavContainer 中了,最后通过 getModelAndView 方法获取了一个 ModelAndView

SpringMVC 源码解析 - 请求执行的过程

进入到该方法下:

private ModelAndView getModelAndView(ModelAndViewContainer mavContainer,
        ModelFactory modelFactory, NativeWebRequest webRequest)
 throws Exception {

    // 更新Model,包括设置 SessionAttributes 和 给Model 设置 BindingResult
    modelFactory.updateModel(webRequest, mavContainer);
    // 请求被完整处理
    if (mavContainer.isRequestHandled()) {
        return null;
    }
    // 获取ModelMap
    ModelMap model = mavContainer.getModel();
    //获取ModelAndView对象 封装请求对应视图和数据
    ModelAndView mav = new ModelAndView(mavContainer.getViewName(), model, mavContainer.getStatus());
    if (!mavContainer.isViewReference()) {
        //设置视图
        mav.setView((View) mavContainer.getView());
    }
    // flash属性填充
    if (model instanceof RedirectAttributes) {
        Map<String, ?> flashAttributes = ((RedirectAttributes) model).getFlashAttributes();
        HttpServletRequest request = webRequest.getNativeRequest(HttpServletRequest.class);
        if (request != null) {
            RequestContextUtils.getOutputFlashMap(request).putAll(flashAttributes);
        }
    }
    return mav;
}

直接创建了一个 ModelAndView 对象,并进行了属性的渲染,到这一步就拿到了 ha.handle 方法的主要目标 ModelAndView 了。

下面再回到 DispatcherServlet 中,继续向下走,如果 ModelAndView为空时, 比如 Handler 返回值为 void, 则根据 request 设置一个默认 view

SpringMVC 源码解析 - 请求执行的过程

再向下走的话则会调用拦截器的 postHandle 方法:

2.7 postHandle

进入到 mappedHandler.applyPostHandle 方法下:

void applyPostHandle(HttpServletRequest request, HttpServletResponse response, @Nullable ModelAndView mv)
        throws Exception {

    for (int i = this.interceptorList.size() - 1; i >= 0; i--) {
        HandlerInterceptor interceptor = this.interceptorList.get(i);
        // 拦截器后置处理
        interceptor.postHandle(request, response, this.handler, mv);
    }
}

和前面 applyPreHandle 方法类似,遍历当前的拦截器,触发后置处理。

再回到 DispatcherServlet 中,再向下执行使用 processDispatchResult 方法,处理上面返回之后的结果:

SpringMVC 源码解析 - 请求执行的过程

2.8 processDispatchResult

进入到该方法下:

private void processDispatchResult(HttpServletRequest request, HttpServletResponse response,
                                   @Nullable HandlerExecutionChain mappedHandler, @Nullable ModelAndView mv,
                                   @Nullable Exception exception)
 throws Exception {
    //是否为错误视图
    boolean errorView = false;

    // 如果存在异常
    if (exception != null) {
        // ModelAndViewDefiningException 异常处理
        if (exception instanceof ModelAndViewDefiningException) {
            logger.debug("ModelAndViewDefiningException encountered", exception);
            mv = ((ModelAndViewDefiningException) exception).getModelAndView();
        } else {
            // 其他异常处理
            Object handler = (mappedHandler != null ? mappedHandler.getHandler() : null);
            // 统一异常处理,并未阻断流程
            mv = processHandlerException(request, response, handler, exception);
            errorView = (mv != null);
        }
    }

    // Did the handler return a view to render?
    // 视图渲染
    if (mv != null && !mv.wasCleared()) {
        // 渲染视图,具体在 render方法中执行
        render(mv, request, response);
        if (errorView) {
            WebUtils.clearErrorRequestAttributes(request);
        }
    } else {
        if (logger.isTraceEnabled()) {
            logger.trace("No view rendering, null ModelAndView returned.");
        }
    }

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

    if (mappedHandler != null) {
        // Exception (if any) is already handled..
        // 发出请求处理完成的通知,触发 Interceptor 的 afterCompletion
        mappedHandler.triggerAfterCompletion(request, response, null);
    }
}

在该方法中进行了视图的渲染,并在最后触发了 Interceptor 的 afterCompletion,这里看下视图渲染方法 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 != null ? this.localeResolver.resolveLocale(request) : request.getLocale());
    response.setLocale(locale);

    View view;
    String viewName = mv.getViewName();
    if (viewName != null) {
        // We need to resolve the view name.
        view = resolveViewName(viewName, 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.isTraceEnabled()) {
        logger.trace("Rendering view [" + view + "] ");
    }
    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 + "]", ex);
        }
        throw ex;
    }
}

在该方法中主要调用了 view.render 完成视图解析,该方法则是 AbstractView 类下的 render 方法:

public void render(@Nullable Map<String, ?> model, HttpServletRequest request,
        HttpServletResponse response)
 throws Exception {

    if (logger.isDebugEnabled()) {
        logger.debug("View " + formatViewName() +
                ", model " + (model != null ? model : Collections.emptyMap()) +
                (this.staticAttributes.isEmpty() ? "" : ", static attributes " + this.staticAttributes));
    }

    //用于把参数的模型 与内置模型属性合并
    //合并顺序为:本视图的所有静态属性、当前请求的路径,传入的模型参数及封装好的请清求上下文
    //请求上下文中包含了主题源与信息源的相关内容
    //暴露的这些属性可以在后续处理中使用,以实现各种功能
    Map<String, Object> mergedModel = createMergedOutputModel(model, request, response);
    // 为视图设置相应的请求头
    prepareResponse(request, response);
    //将model 与视图进行整合
    renderMergedOutputModel(mergedModel, getRequestToExpose(request), response);
}

这里进行了模型属性的合并,最终使用 renderMergedOutputModel 方法将model 与视图进行整合,该方法为抽象方法,由子类实现具体逻辑:

SpringMVC 源码解析 - 请求执行的过程

这里主要看 InternalResourceView 下的 renderMergedOutputModel 方法:

protected void renderMergedOutputModel(
        Map<String, Object> model, HttpServletRequest request, HttpServletResponse response)
 throws Exception {

    // 将模型对象作为请求属性公开
    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).
    // 构造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 (useInclude(request, response)) {
        response.setContentType(getContentType());
        if (logger.isDebugEnabled()) {
            logger.debug("Including [" + getUrl() + "]");
        }
        rd.include(request, response);
    }

    else {
        // Note: The forwarded resource is supposed to determine the content type itself.
        if (logger.isDebugEnabled()) {
            logger.debug("Forwarding to [" + getUrl() + "]");
        }
        // 转发
        rd.forward(request, response);
    }
}

下面再回到 DispatcherServlet 中,再继续向下看,如果发生了异常,则触拦截器的 afterCompletion 方法,将异常传递出去:

SpringMVC 源码解析 - 请求执行的过程

最后在 finally 中判断是否异步或文件上传,进行结尾操作:

SpringMVC 源码解析 - 请求执行的过程


原文始发于微信公众号(狂热JAVA小毕超):SpringMVC 源码解析 – 请求执行的过程

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/241062.html

(0)
小半的头像小半

相关推荐

发表回复

登录后才能评论
极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!