马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有账号?立即注册
×
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">
-
- <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>
-
- </init-param>
-
- <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" >
- <property name="prefix" value="/"/>
-
- <property name="suffix" value=".jsp"/>
- </bean>
-
- <mvc:annotation-driven/>
-
- <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 NameDepends OnTypeDescriptiontomcatRun-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-test-mvc/index

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">
-
- <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>
-
- </init-param>
-
- <load-on-startup>1</load-on-startup>
- </servlet>
- <servlet-mapping>
- <servlet-name>mvc</servlet-name>
- <url-pattern>/</url-pattern>
- </servlet-mapping>
- </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-test-mvc/index,背后到底做了哪些事情
目标: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);
- }
- }
复制代码本文由传智教育博学谷教研团队发布。
如果本文对您有帮助,欢迎关注和点赞;如果您有任何建议也可留言评论或私信,您的支持是我坚持创作的动力。
转载请注明出处!
|