乐趣区

关于java:爱上源码重学Spring-MVC深入

1.1 gradle 搭建源码调试环境

1)搭建 gradle 环境

4 个步骤

1、File-New-Module

抉择 java 和 web

2、填写包信息

3、存储门路

2)减少起步依赖

依赖的我的项目,间接复制粘贴下来

1、对 spring 的依赖

2、对 MVC 的依赖

3、对 Tomcat 插件的依赖

build.gradle

group 'com.spring.test'
version '5.0.2.RELEASE'

apply plugin: 'java'
apply plugin: 'war'
apply plugin: 'com.bmuschko.tomcat' //tomcat: 插件
// tomcat: 以下配置会在第一次启动时下载插件二进制文件
// 在我的项目根目录中执行 gradle tomcatRun
buildscript {
    repositories {jcenter()
    }

    dependencies {classpath 'com.bmuschko:gradle-tomcat-plugin:2.5'}
}
// 配置阿里源
allprojects {
    repositories {maven{ url 'http://maven.aliyun.com/nexus/content/groups/public/'}
    }
}


dependencies {
    testCompile group: 'org.testng', name: 'testng', version: '6.14.3'
    runtime 'javax.servlet:jstl:1.1.2' // Servlet 容器必须
    compile(project(':spring-context'))
    compile(project(':spring-web'))
    compile(project(':spring-webmvc'))

    // tomcat: 将 Tomcat 运行时库增加到配置 tomcat 中: (此处为 Tomcat9)
    def tomcatVersion = '9.0.1'
    tomcat "org.apache.tomcat.embed:tomcat-embed-core:${tomcatVersion}",
            "org.apache.tomcat.embed:tomcat-embed-logging-juli:9.0.0.M6",
            "org.apache.tomcat.embed:tomcat-embed-jasper:${tomcatVersion}"
}

// tomcat: 一些协定设置(留神,这里必须加上,不然会抛 tomcat 的异样,仅限 tomcat9)tomcat {
    httpProtocol = 'org.apache.coyote.http11.Http11Nio2Protocol'
    ajpProtocol  = 'org.apache.coyote.ajp.AjpNio2Protocol'
}



// UTF-8
tasks.withType(JavaCompile) {options.encoding = "UTF-8"}

3)MVC 代码编写

前提:

减少 WEB-INF 目录和 Web.xml

1、关上 File – Proect Structrue

2、选中方才的 mvc 我的项目,开展,选中 web gradle,到左边 点击加号

3、确认门路

spring-mvc-test\src\main\webapp\WEB-INF\web.xml

WEB-INF 和 xml 创立结束

webapp/WEB-INF/web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
         version="4.0">

    <!-- Spring MVC 配置 -->
    <servlet>
        <servlet-name>mvc</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>classpath:mvc-servlet.xml</param-value>
            <!--<param-value>/WEB-INF/mvc-servlet.xml</param-value>-->
        </init-param>
        <!-- load-on-startup 元素标记容器是否在启动的时候就加载这个 servlet(实例化并调用其 init()办法) -->
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>mvc</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>

</web-app>

resources/mvc-servlet.xml

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

    <!-- 开启注解扫描 -->
    <context:component-scan base-package="com.spring.mvc.test"/>
    <!-- 视图解析器对象 -->
    <bean id="internalResourceViewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/"/>
        <!--<property name = "prefix" value="/WEB-INF/"></property>-->
        <property name="suffix" value=".jsp"/>
    </bean>
    <!-- 开启 SpringMVC 框架注解的反对 -->
    <mvc:annotation-driven/>
    <!-- 动态资源 (js、image 等) 的拜访 -->
    <mvc:default-servlet-handler/>

</beans>

webapp/index.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
  <head>
    <title>SpringMvc 源码深刻分析 </title>
  </head>
  <body>
  Gradle 构建 Spring MVC 例子....
  </body>
</html>

MvcController.java

package com.spring.mvc.test;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.ModelAndView;

@Controller
public class MvcController {@RequestMapping("/index")
    public ModelAndView getModeAndView() {
        // 创立一个模型视图对象
        ModelAndView mav = new ModelAndView("index");
        return mav;
    }
    @RequestMapping("/text")
    @ResponseBody
    public String text() {return "Text...";}

}

4)启动 MVC 我的项目

两种启动形式

形式一:外挂启动

idea 环境里面启动(我的项目根目录下运行 gradle + task name)

Task Name Depends On Type Description
tomcatRun TomcatRun 启动 Tomcat 实例并将 Web 应用程序部署到该实例。
tomcatRunWar TomcatRunWar 启动 Tomcat 实例并将 WAR 部署
tomcatStop TomcatStop 进行 Tomcat 实例
tomcatJasper TomcatJasper 运行 JSP 编译器并应用 Jasper 将 JSP 页面转换为 Java 源代码。

在我的项目根目录中执行gradle tomcatRun

# 动 Tomcat 实例并将 Web 应用程序部署到该实例
gradle  tomcatRun
#进行 Tomcat 实例
gradle tomcatStop

控制台失常输入

形式二:集成到 idea 中启动

设置

即可点击运行

运行胜利

形式三:

idea 左边找到 gradle 的 task,间接双击,这个爽~

拜访 MVC 我的项目

留神:spring-test-mvc 是我的项目的名称

http://localhost:8080/spring-test-mvc/index

成果如下

5)源码调试配置

idea 里的调试

简略,debug 模式启动 tomcat 即可

近程调试模式

重要

想要近程 debug,须要应用下面的办法二,因为 debug 启动须要设置 gradle 的环境变量,

即运行 gradle 命令的时候插入一些参数命令。

减少 debug 参数,对外裸露 5005 端口,即监听 5005 端口。

-Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=5005

在配置 Remote;监听 5005 端口

点击 + 号,创立 Remote;默认配置即可

最初一步

1、先运行 tomcat

2、再运行 remote

http://localhost:8080/spring-test-mvc/index

打上断点试试!

包含咱们之前 ioc 里的 bean 创立等中央,轻易打。

1.2 MVC 工作原理和继承关系

1)MVC 底层工作原理

指标:意识 SpringMVC 的工作原理(对照源码),如何找到对应的 Controller,进行页面渲染的

步骤:11 步

源头:http://localhost:8080/spring-…

SpringMVC 工作原理

1、DispatcherServlet(前端控制器) 是个 servlet,负责接管 Request 并将 Request 转发给对应的解决组件。

2、HanlerMapping(处理器映射器)是 SpringMVC 中实现 url 到 Controller 映射的组件。DispatcherServlet 从 HandlerMapping 查找解决 Request 的 Controller,

3、HanlerMapping 返回一个执行器链(url 到 Controller 映射的组件)给 DispatcherServlet

4、DispatcherServlet 申请处理器适配器 HandlerAdapter

5、处理器适配器 HandlerAdapter 去拜访咱们的 handler(controller)

6、handler(controller)返回 ModelAndView 给处理器适配器 HandlerAdapter

7、处理器适配器 HandlerAdapter 返回 ModelAndView 给 DispatcherServlet

8、DispatcherServlet 申请 ViewResolver 视图解析器

9、ViewResolver 视图解析器返回 view 给 DispatcherServlet

10、DispatcherServlet 申请 view 做页面解析和渲染

11、view 将渲染好的数据返回给 DS,DS 将渲染好的字符流给 client,看到了页面!

2)MVC 外围类继承关系

指标:简略意识 MVC 的继承关系

tips

不要求记住

DispatcherServlet 前端总控制器(webmvc 源码)

FrameworkServlet (webmvc 源码)

HttpServletBean 是的一个简略扩大类((webmvc 源码)

HttpServlet(servlet API,曾经来到了 spring mvc 的管制范畴)

1.3 Spring MVC 源码深刻分析

引言:以后源码解说思路
1、断点调试
2、流程图对照
3、继承关系对照

1.3.1 MVC 启动阶段

留神,这个阶段没法 debug,咱们从 servlet 标准去间接看源码

上面的申请阶段,再具体 debug 申请链路的残缺过程

web.xml 回顾

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
         version="4.0">

    <!-- Spring MVC 配置 -->
    <servlet>
        <servlet-name>mvc</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>classpath:mvc-servlet.xml</param-value>
            <!--<param-value>/WEB-INF/mvc-servlet.xml</param-value>-->
        </init-param>
        <!-- load-on-startup 元素标记容器是否在启动的时候就加载这个 servlet(实例化并调用其 init()办法) -->
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>mvc</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>
    

     <!-- 初始化 Spring icC 容器 -->
    <!--<context-param>-->
        <!--<param-name>contextConfigLocation</param-name>-->
    <!-- 默认的门路是 /WEB-INF/applicationontext.xml, 上面多个 xml 应用,宰割 -->
        <!--<param-value>classpath: applicationContext-ZH.xml</param-value>-->
    <!--</context-param>-->
    <!-- 要应用 Spring 的 IoC 容器 -->
    <!--<listener>-->
        <!--<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>-->
    <!--</listener>-->

</web-app>

从下面的配置,咱们能够看出,web.xml 中的 DS 是一个 servlet,那就从 java web 的 servlet 标准说起

下面类关系,咱们说过,springmvc 的领域里,最顶层的是 HttpServletBean 继承的 规范 HttpServlet

1、ioC Bean 初始化

org.springframework.web.servlet.HttpServletBean#init

2、9 大组件初始化(ioC)

org.springframework.web.servlet.HttpServletBean#init

启动:servlet 标准,init 办法被容器调用

在 servlet 实例化后,被容器调用一次 init 办法,所以启动咱们找到 mvc 里的父类从 init 看起

总结:办法调用关系(伪代码)

HttpServletBean{init(){protected initServletBean();
  }
}

FrameworkServlet extends HttpServletBean{
  @Override
  initServletBean(){initWebApplicationContext(){WebApplicationContext wac = createWebApplicationContext(rootContext);
      protected onRefresh(wac); 
    }
  }
}

DispatcherServlet extends FrameworkServlet{onRefresh(wac){initStrategies(wac){
          // 多文件上传的组件
        initMultipartResolver(context);
        // 初始化本地语言环境
        initLocaleResolver(context);
        // 初始化模板处理器
        initThemeResolver(context);
        // 初始化处理器映射器
        initHandlerMappings(context);
        // 初始化处理器适配器
        initHandlerAdapters(context);
        // 初始化异样拦截器
        initHandlerExceptionResolvers(context);
        // 初始化视图预处理器
        initRequestToViewNameTranslator(context);
        // 初始化视图转换器
        initViewResolvers(context);
        //FlashMap 管理器
        initFlashMapManager(context);
    }
  }
}

1.3.2 MVC 申请阶段

需要:咱们在浏览器输出 http://localhost:8080/spring-…,背地到底做了哪些事件

指标:MVC 如何通过一个 url 就能找到咱们的 controller,并返回数据

1、断点调试
2、流程图对照
3、继承关系对照

流程图解:

规范 Servlet(回顾 tomcat 源码里,容器最初调的是 wrapper 的 service 办法)

伪代码

interface Servlet{service()  // 1  , 规范 servlet 标准的入口
}

HttpServlet implements Servlet{public service(ServletRequest req, ServletResponse res){
        // 转成 HttpServletRequest
        protected service(req,res);  // 2
    }
    protected service(HttpServletRequest req, HttpServletResponse resp){if(isGet){protected doGet()  // 4
        }        
    }
    protected void doGet(HttpServletRequest req, HttpServletResponse resp);  // 5
}

//spring mvc

FrameworkServlet extends HttpServlet{
    @Override
    service(){super.service();  // 3
    }
    
    protected void doGet(HttpServletRequest req, HttpServletResponse resp){processRequest(request, response){protected doService(request, response); // 6
        }    
    }
}

DispatcherServlet extends FrameWorkServlet{protected doService(request, response);  //  7  , here!
}

代码查找的门路:

tips:

spring mvc 的 FrameworkServlet,这是咱们源码跟踪的入口

我的项目启动

拜访

http://localhost:8080/spring-test-mvc/index

上图的初始化流程在源码中是怎么流转的呢?

入口:开启申请的大门

org.springframework.web.servlet.FrameworkServlet:

java web 规范通知咱们,request 的 get 会交给规范 HttpServlet 的 doGet 办法

而这个类 FrameworkServlet,是 HttpServlet 的子类,笼罩了上述的 doGet,

所以,申请进入 spring 的第一入口,就在这里!!!

1)org.springframework.web.servlet.FrameworkServlet#doGet

调用到了 org.springframework.web.servlet.FrameworkServlet#doGet

    //get 申请调用
    @Override
    protected final void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {processRequest(request, response);
    }

2)org.springframework.web.servlet.FrameworkServlet#processRequest

//    重点关注:doService
    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());

        initContextHolders(request, localeContext, requestAttributes);

        try {
            // 重点查看,跳到 DispatcherServlet 类中(子类重写)doService(request, response);
        } catch (ServletException | 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);
        }
    }

3)org.springframework.web.servlet.DispatcherServlet#doService

    // 重写父类
    // 重点关注  doDispatch(request, response);
    @Override
    protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {if (logger.isDebugEnabled()) {String resumed = WebAsyncUtils.getAsyncManager(request).hasConcurrentResult() ? "resumed" : "";
            logger.debug("DispatcherServlet with name'" + getServletName() + "'"+ resumed +" processing "+ request.getMethod() +" request for ["+ getRequestUri(request) +"]");
        }

        // Keep a snapshot of the request attributes in case of an include,
        // to be able to restore the original attributes after the include.
        Map<String, Object> attributesSnapshot = null;
        if (WebUtils.isIncludeRequest(request)) {attributesSnapshot = new HashMap<>();
            Enumeration<?> attrNames = request.getAttributeNames();
            while (attrNames.hasMoreElements()) {String attrName = (String) attrNames.nextElement();
                if (this.cleanupAfterInclude || attrName.startsWith(DEFAULT_STRATEGIES_PREFIX)) {attributesSnapshot.put(attrName, request.getAttribute(attrName));
                }
            }
        }

        // 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());

        if (this.flashMapManager != null) {FlashMap inputFlashMap = this.flashMapManager.retrieveAndUpdate(request, response);
            if (inputFlashMap != null) {request.setAttribute(INPUT_FLASH_MAP_ATTRIBUTE, Collections.unmodifiableMap(inputFlashMap));
            }
            request.setAttribute(OUTPUT_FLASH_MAP_ATTRIBUTE, new FlashMap());
            request.setAttribute(FLASH_MAP_MANAGER_ATTRIBUTE, this.flashMapManager);
        }

        try {
            // 重点关注
            doDispatch(request, response);
        }
        finally {if (!WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) {
                // Restore the original attribute snapshot, in case of an include.
                if (attributesSnapshot != null) {restoreAttributesAfterInclude(request, attributesSnapshot);
                }
            }
        }
    }

进入外围

4)org.springframework.web.servlet.DispatcherServlet#doDispatch

//    Spring MVC 的最外围代码
    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 {
                // 申请查看,是否文件上传申请(二进制申请)processedRequest = checkMultipart(request);
                multipartRequestParsed = (processedRequest != request);

//                依据以后的申请去拿一个 Handler. 这个 Handler 其实就是咱们的控制器,进入!!!!!mappedHandler = getHandler(processedRequest);
                if (mappedHandler == null) {noHandlerFound(processedRequest, response);
                    return;
                }

                // 处理器适配器,9 大组件初始化
                HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());

                // Process last-modified header, if supported by the handler.
                String method = request.getMethod();
                //get 办法为 true
                boolean isGet = "GET".equals(method);
                //method 为 get
                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;}
                }

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

                // 执行咱们的业务控制器办法,com.spring.mvc.test.MvcController.getModeAndView
                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);
                }
            }
        }
    }

5)org.springframework.web.servlet.DispatcherServlet#getHandler

    @Nullable
    protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
        // 不止一个,比方 BeanNameHandlerMapping、SimpleUrlHandlerMapping,还有咱们须要的 RequestHandlerMapping
        // 在 9 个组件初始化的时候赋值
        if (this.handlerMappings != null) {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;
    }

org.springframework.web.servlet.DispatcherServlet#getHandlerAdapter

    protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {if (this.handlerAdapters != null) {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");
    }

6)调用业务 Controller

// 执行咱们的业务控制器办法,com.spring.mvc.test.MvcController.getModeAndView
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter#handleInterna

    @Override
    protected boolean supportsInternal(HandlerMethod handlerMethod) {return true;}

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

7)org.springframework.web.servlet.DispatcherServlet#processDispatchResult

//1、申请视图解析器,解析成 view
    //2、执行页面渲染
    private void processDispatchResult(HttpServletRequest request, HttpServletResponse response,
            @Nullable HandlerExecutionChain mappedHandler, @Nullable ModelAndView mv,
            @Nullable Exception exception) throws Exception {

        boolean errorView = false;
       // 如果异样不为空
        if (exception != null) {if (exception instanceof ModelAndViewDefiningException) {logger.debug("ModelAndViewDefiningException encountered", exception);
                mv = ((ModelAndViewDefiningException) exception).getModelAndView();}
            else {Object handler = (mappedHandler != null ? mappedHandler.getHandler() : null);
                mv = processHandlerException(request, response, handler, exception);
                errorView = (mv != null);
            }
        }

        // 视图渲染,响应视图
        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);
        }
    }

如果本文对您有帮忙,欢送 关注 点赞`,您的反对是我保持创作的能源。

转载请注明出处!

退出移动版