SpringMVC请求处理源码解析

Spring mvc源码解析

在这里插入图片描述

页面请求路径分析:

在这里插入图片描述

SpringMVC处理请求:
DispatchServlet ----> 接受请求 ---> path,request parameters ---> path --> @RequestMapping method   --->解析参数,参数绑定 --->执行方法--->返回值解析
																		 bean对象(实现Controller接口的对象)

请求步骤:

  1. 启动Tomcat

创建Tomcat容器,占用8080端口启动Tomcat中spring_mvc_helloworld应用。

  1. 解析web.xml文件

解析web.xml文件中内容,创建相应对象实例和其他配置功能

核心就是创建DispatchServlet

在这里插入图片描述

  1. 创建DispatchServlet对象

DispatchServlet处理请求核心代码:

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);
				
				// 获取HandlerMapping
				mappedHandler = getHandler(processedRequest);
				if (mappedHandler == null) {
					noHandlerFound(processedRequest, response);
					return;
				}

				// 根据HandlerMapping获取HandlerAdapter(适配器模式)
				HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());

				// 获得方法类型
				String method = request.getMethod();
                // 判断是否是get请求
				boolean isGet = HttpMethod.GET.matches(method);
				if (isGet || HttpMethod.HEAD.matches(method)) {
					long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
					if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
						return;
					}
				}

                //判断是否执行Handler前置处理
				if (!mappedHandler.applyPreHandle(processedRequest, response)) {
					return;
				}

				// 执行方法,并返回视图和数据 ---核心处理
				mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

				if (asyncManager.isConcurrentHandlingStarted()) {
					return;
				}
				
                //完成默认视图名
				applyDefaultViewName(processedRequest, mv);
                //完成Handler的后置处理
				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);
				}
			}
		}
	}

3.1、初始化DispatchServlet

​ 调用DispatchServlet.init()初始化方法,如果没有定义init方法,会自动调用父类HttpServletBean中的init()方法初始化

DispatchServlet初始化方法在父类中已经重写

DispatchServlet.init() —> 创建Spring容器
—> initStrategies()

​ —>initMultipartResolver(context);

​ initLocaleResolver(context);
​ initThemeResolver(context);
​ initHandlerMappings(context);
​ initHandlerAdapters(context);
​ initHandlerExceptionResolvers(context);
​ initRequestToViewNameTranslator(context);
​ initViewResolvers(context);
​ initFlashMapManager(context);

例:

initHandlerMappings(context);

—> 创建RequestMapingHadlerMapping —> afterPropertiesSet()
—> 创建RequestMapingHadlerAdapter ---->afterPropertiesSet()
—> 创建BeanNameUrlHandlerMapping —> detectHandler()
—> 创建RouterFunctionMapping —> afterPropertiesSet()

3.2、init()初始化方法

DispatchServlet的父类FarmeworkServlet中有属性WebApplicationContext,就是DispatchServlet内部的IOC容器,

在FarmeworkServlet进行IOC容器创建。

protected WebApplicationContext createWebApplicationContext(@Nullable ApplicationContext parent) {
		//创建哪类IOC容器,默认是XmlWebApplicationContext类型
        Class<?> contextClass = this.getContextClass();
        if (!ConfigurableWebApplicationContext.class.isAssignableFrom(contextClass)) {
            throw new ApplicationContextException("Fatal initialization error in servlet with name '" + this.getServletName() + "': custom WebApplicationContext class [" + contextClass.getName() + "] is not of type ConfigurableWebApplicationContext");
        } else {
        	//创建XmlWebApplicationContext对象实例
            ConfigurableWebApplicationContext wac = (ConfigurableWebApplicationContext)BeanUtils.instantiateClass(contextClass);
            wac.setEnvironment(this.getEnvironment());
            wac.setParent(parent); //父容器
            // this.getContextConfigLocation();获取到web.xml文件中配置的init-param的contextConfigLocation属性
            String configLocation = this.getContextConfigLocation();
            if (configLocation != null) {
                wac.setConfigLocation(configLocation);
            }
			//创建和刷新IOC容器,就会根据配置文件扫描组件,将组件注入IOC
            this.configureAndRefreshWebApplicationContext(wac);
            return wac;
        }
    }

3.3、Hadler:处理器 -->定义处理此url请求的处理器

SpringMVC中一共提供了三种Hadler:

1.@RequestMapping注解:标注了此注解,请求的路径映射到标注的方法或类上就是一个Handler,可以进行方法调用。(常用)

2.实现Controller接口的bean对象,就成为一个Hadler,实现接口中handleRequest方法,进行逻辑处理。此时这个类需要放到IOC容器中,并标明请求路径.例:@Component(“/hello”).

3.实现HttpRequestHandler接口的bean对象,就成为一个Hadler,原理与2类似。

4.RouterFunction对象

3.4 HandlerMapping:处理器映射器–>将url与方法进行映射

HandlerMapping初始化:将标注有@Controller和@RequestMapping注解的方法或类,还有实现Controller接口,实现HttpRequestHandler接口,RouterFunctiond对象的Handler进行请求与方法映射

在FrameworkServlet中有SpringIOC容器监听器ContextRefreshListener,监听SpringIOC容器创建,创建完毕后,DispatchServlet会调用onRefresh方法,此时就会再进行一些初始化。

protected void onRefresh(ApplicationContext context) {
    this.initStrategies(context);
}

protected void initStrategies(ApplicationContext context) {
    this.initMultipartResolver(context);
    this.initLocaleResolver(context);
    this.initThemeResolver(context);
    this.initHandlerMappings(context);
    this.initHandlerAdapters(context);
    this.initHandlerExceptionResolvers(context);
    this.initRequestToViewNameTranslator(context);
    this.initViewResolvers(context);
    this.initFlashMapManager(context);
}

SpringMVC根据Hadler类型提供了三种HandlerMapping,分别用于不同Hadler的映射关系:

1.RequestMappingHandlerMapping

—>最终将RequestMapping注解与方法映射关系存入Map—>Map<RequestInfo,HandleMethod>

2.BeanNameUrlHandlerMapping -->因为实现Controller和HttpRequestHandler两个HadlerMapping都是创建了类似的bean(样
式:@Component(“/hello”)),所以两种使用一个BeanNameUrlHandlerMapping 进行bean的查找。

原理:寻找哪个bean的名称是以/开头,找到作为Handler,存入Map—》Map<path,bean对象>

3.RouterFunctionMapping

以RequestMappingHandlerMapping 源码为例,DispachServlet的initStrategies方法的initHandlerMappings

private void initHandlerMappings(ApplicationContext context) {
    this.handlerMappings = null;
    //根据类型判断是否有自定义的HadlerMapping
    if (this.detectAllHandlerMappings) {
    	//创建一个存放HadlerMapping的Map,此时Spring提供的HadlerMapping并没有放入Map中
        Map<String, HandlerMapping> matchingBeans = BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerMapping.class, true, false);
        if (!matchingBeans.isEmpty()) {
            this.handlerMappings = new ArrayList(matchingBeans.values());
            AnnotationAwareOrderComparator.sort(this.handlerMappings);
        }
    //根据名字判断是否有自定义的HadlerMapping
    } else {
        try {
        	//将自定义的HadlerMapping放入其中
            HandlerMapping hm = (HandlerMapping)context.getBean("handlerMapping", HandlerMapping.class);
            this.handlerMappings = Collections.singletonList(hm);
        } catch (NoSuchBeanDefinitionException var4) {
        }
    }
	//如果没有自定义的HadlerMapping,就使用Spring默认提供的三种HadlerMapping
    if (this.handlerMappings == null) {
        //取默认的handlerMappings,在DispatchServlet.properties配置文件中有默认配置,进行读取.
        //将读取的默认类创建为Bean对象,放入IOC容器中
        this.handlerMappings = this.getDefaultStrategies(context, HandlerMapping.class);
        if (this.logger.isTraceEnabled()) {
            this.logger.trace("No HandlerMappings declared for servlet '" + this.getServletName() + "': using default strategies from DispatcherServlet.properties");
        }
    }

    Iterator var6 = this.handlerMappings.iterator();

    while(var6.hasNext()) {
        HandlerMapping mapping = (HandlerMapping)var6.next();
        if (mapping.usesPathPatterns()) {
            this.parseRequestPath = true;
            break;
        }
    }

}

RequestMappingHandlerMapping–>AbstractHandlerMethodMapping:查找标注RequestMapping或controller注解的Handler

protected void initHandlerMethods() {
	//获取Spring容器中所有bean的名字
    String[] var1 = this.getCandidateBeanNames();
    int var2 = var1.length;

    for(int var3 = 0; var3 < var2; ++var3) {
        String beanName = var1[var3];
        if (!beanName.startsWith("scopedTarget.")) {
            //判断bean的类型
            this.processCandidateBean(beanName);
        }
    }

    this.handlerMethodsInitialized(this.getHandlerMethods());
}
//判断bean类型
protected void processCandidateBean(String beanName) {
        Class<?> beanType = null;

        try {
            //根据bean的名字获取到类型
            beanType = this.obtainApplicationContext().getType(beanName);
        } catch (Throwable var4) {
            if (this.logger.isTraceEnabled()) {
                this.logger.trace("Could not resolve type for bean '" + beanName + "'", var4);
            }
        }
		//this.isHandler(beanType)判断这个类是否标注了Controller注解或RequestMapping注解
        if (beanType != null && this.isHandler(beanType)) {
            this.detectHandlerMethods(beanName); //根据bean对象名字查找处理方法
        }

    }
}
protected boolean isHandler(Class<?> beanType) {
    return AnnotatedElementUtils.hasAnnotation(beanType, Controller.class) || AnnotatedElementUtils.hasAnnotation(beanType, RequestMapping.class);
}

最终的到所有标有@RequestMapping注解的方法,存入到一个Map中,这个map以path为key,以method为value进行存储

protected void detectHandlerMethods(Object handler) { 
    Class<?> handlerType = handler instanceof String ? this.obtainApplicationContext().getType((String)handler) : handler.getClass();
    if (handlerType != null) {
    	//获取bean的类型
        Class<?> userType = ClassUtils.getUserClass(handlerType);
        //循环所有方法<Method,@RequestMapping注解信息>,并判断是否有@Request注解,将RequestMapping注解上的信息查找后封装为RequestMappingInfo对象
        //Map<Method, T>中key存放的是标注了@RequestMapping注解的方法,value存放的是@RequestMapping的信息RequestMappingInfo对象
        Map<Method, T> methods = MethodIntrospector.selectMethods(userType, (method) -> {
            try {
                return this.getMappingForMethod(method, userType);
            } catch (Throwable var4) {
                throw new IllegalStateException("Invalid mapping on handler class [" + userType.getName() + "]: " + method, var4);
            }
        });
        if (this.logger.isTraceEnabled()) {
            this.logger.trace(this.formatMappings(userType, methods));
        }
		//遍历@RequestMapping方法,转换为指定格式的Map注册到mappingRegistry中,mappingRegistry此时还是Map<Path,HandlerMapping>
        //经过注册,最后生成指定格式的map,Map<RequestMappingInfo,Method>-->最终存入AbstractHandlerMethodMapping的mappingRegistry中
        methods.forEach((method, mapping) -> {
            Method invocableMethod = AopUtils.selectInvocableMethod(method, userType);
            this.registerHandlerMethod(handler, invocableMethod, mapping);
        });
    }

}

初始化完成后,生成方法或类与路径或@RequestMapping注解映射的Map,根据请求从Map中获取对应HandlerMapping:

DispatchServlet.doDispatch() —>getHandler()

protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
    if (this.handlerMappings != null) {
        for (HandlerMapping mapping : this.handlerMappings) {
            HandlerExecutionChain handler = mapping.getHandler(request);
            if (handler != null) {
                return handler;
            }
        }
    }
    return null;
}

mapping.getHandler(request)—>getHandlerInternal(request)—>lookupHandlerMethod(lookupPath, request)—>List directPathMatches = this.mappingRegistry.getMappingsByDirectPath(lookupPath);

根据url中的请求路径从Map,this.mappingRegistry中匹配路径key,得到Value就是对应的加了@RequestMapping注解的RequestMappingInfo信息,最终得到Handler

根据url找到具体handle方法
AbstractHandlerMethodMapping类中的lookupHandlerMethod方法

//从已经存有的mappingRegistry的Map对象中匹配路径,查找对应的方法
List<T> directPathMatches = this.mappingRegistry.getMappingsByDirectPath(lookupPath);
  1. SpringMVC父子容器(!不常用)

在这里插入图片描述

当一个Tomcat程序有多个DispatchServlet时,每个DispatchServlet都有一个Spring容器,每个容器中的bean不相同,如果想要多个DispatchServlet容器共用一个bean对象,就需要创建一个父容器来实现不同DispatchServlet公用一个Bean。

创建父容器在创建DispatchServlet之前!!!!

如何创建父容器?

在web.xml文件中

<listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>

<context-param>
    <param-name>contextConfigLocation</param-name> 
    <param-value>/WEB-INF/spring-parent.xml</param-value>     <!--父容器配置文件-->
</context-param>

在Tomcat初始化时,通过这个监听器,会根据配置先创建父容器,然后再创建其他子容器

创建完父容器会将容器存入ServletContext(应用上下文)中,创建完成各个DispatchServlet容器后,在FrameworkServlet类中initWebApplicationContext()设置父子容器关系

protected WebApplicationContext initWebApplicationContext() {
    //获取到父容器
    WebApplicationContext rootContext = WebApplicationContextUtils.getWebApplicationContext(this.getServletContext());
    WebApplicationContext wac = null;

    if (wac == null) {
        //创建子容器时,将父容器传入,设置父子容器
        wac = this.createWebApplicationContext(rootContext);
    }


    return wac;
}
  1. TomCat启动完成

  2. DispatchServlet处理请求

HandlerAdapter:处理器适配器(适配器模式)

SpringMvc根据HandlerMapping创建了多种相对应的HandlerAdapter

1.标注的@RequesMapping -----> RequestMappingHandlerAdapter

2.HttpRequestHandler ----->HttpRequestHandlerAdapter

3.实现Controller接口对象 ----->SimpleControllerHandlerAdapter

4.HandlerFunction对象 ----->HandlerFunctionAdapter

3和4都是实现接口,然后返回对象,放入Spring容器中,处理请求时,使用这两种方法的都会使用SimpleControllerHandlerAdapter适配器。

传入不同的HandlerMapping得到不同HandlerAdapter,执行各自handle方法,来执行HandlerMapping中的Map的对应的方法.

DispatchServlet.getHandlerAdapter()–

这里以有@RequestMapping注解的Handler处理器为例,根据Handler处理器找到相应Adapter适配器(RequestMappingHandlerAdapter)—
在这里插入图片描述

DispatchServlet中:

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

6.参数解析流程

在这里插入图片描述

请求到达之前的初始化

1、初始化数据/参数绑定器

@InitBinder

@InitBinder从字面意思可以看出这个的作用是给Binder做初始化的,@InitBinder主要用在@Controller中标注于方法上(@RestController也算),表示初始化当前控制器的数据绑定器(或者属性绑定器),只对当前的Controller有效。@InitBinder标注的方法必须有一个参数WebDataBinder。所谓的属性编辑器可以理解就是帮助我们完成参数绑定,然后是在请求到达controller要执行方法前执行

用法:

@InitBinder
private void initBinder(WebDataBinder binder) {
	// 可用于自定义参数校验,然后通过addValidators来进行绑定controller
    binder.addValidators(userValidator);
    // 可用于注册 属性编译器
    binder.registerCustomEditor(String.class,new StringTrimmerEditor(true));
}

WebDataBinder

WebDataBinder的作用是从Web 请求中,把请求里的参数都绑定到对应的JavaBean上!在Controller方法中的参数类型可以是基本类型,也可以是封装后的普通Java类型。若这个普通的Java类型没有声明任何注解,则意味着它的每一个属性都需要到Request中去查找对应的请求参数,而WebDataBinder则可以帮助我们实现从Request中取出请求参数并绑定到JavaBean中。

我们知道通过@InitBinder修饰的可以拿到WebDataBinder,WebDataBinder 其实已经帮我们完成了基本的参数映射,日期类型就是个特殊的

使用get请求params传date类型,SpringMVC在默认时,是不支持这种类型转换的。此时我们就需要自定义编译器,然后通过binder.registerCustomEditor注册进去。post请求json传参默认是支持yyyy-MM-dd其他格式也会报错的!
当然除此外在日期类型字段上添加@DateTimeFormat(pattern = “yyyy-MM-dd HH:mm:ss”) 也是可以的。

2、数据绑定器

关于Date属性绑定器有两种方案:使用spring提供的CustomDateEditor,另外一种就是自定义PropertyEditorSuppotr

@RequestMapping("body")
@RestController
public class RequestBodyController {

    @GetMapping("/test")
    public Params request(Params params) {
        System.out.println(params);
        return params;
    }

    @InitBinder
    public void initBinder(WebDataBinder binder) {
        // 格式化date方式一:get请求params传参必须传yyyy-MM-dd HH:mm:ss,否则400错误
        // post请求json传参只能传yyyy-MM-dd,如果传其他格式,连这个方法都进不来就400异常了
        DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        CustomDateEditor dateEditor = new CustomDateEditor(df, true);
        binder.registerCustomEditor(Date.class, dateEditor);

//        // 格式化date方式二,自定义PropertyEditorSupport,然后利用hutool的格式化,DateUtil.parse支持的格式有很多种,这里支持很多种是可以传入任何格式,他都会给你格式化成yyyy-MM-dd HH:mm:ss
		// 日期没有时分秒的时候格式化出来的是2022-10-11 00:00:00
        // 自定义的这种方式对于json传参方式没有效果,压根连方法都不会进入
//        binder.registerCustomEditor(Date.class, new PropertyEditorSupport() {
//            @Override
//            public void setAsText(String text) {
//                System.out.println("1111");
//                // DateUtil.parse是hutool当中的方法,hutool是一个Java工具包
//                setValue(DateUtil.parse(text));
//            }
//        });

		// 格式化string:如果是字符串类型,就去除字符串的前后空格
        binder.registerCustomEditor(String.class,
                new StringTrimmerEditor(true));
    }

}

3、全局数据绑定器

3.1. 方式一:@ControllerAdvice

@InitBinder方法只对当前Controller生效,要想全局生效,可以使用@ControllerAdvice。通过@ControllerAdvice可以将对于控制器的全局配置放置在同一个位置,注解了@ControllerAdvice的类的方法可以使用@ExceptionHandler,@InitBinder,@ModelAttribute注解到方法上,这对所有注解了@RequestMapping的控制器内的方法有效

@ControllerAdvice
public class GlobalControllerAdvice {

    @InitBinder
    public void initBinder(WebDataBinder binder) {
        binder.registerCustomEditor(String.class,
                new StringTrimmerEditor(true));

        binder.registerCustomEditor(Date.class, new PropertyEditorSupport() {
            @Override
            public void setAsText(String text) {
                // DateUtil.parse是hutool当中的方法
                setValue(DateUtil.parse(text));
            }
        });
    }
}

3.2. 方式二:RequestMappingHandlerAdapter

@Configuration
public class Config {

    @Bean
    public RequestMappingHandlerAdapter webBindingInitializer(RequestMappingHandlerAdapter requestMappingHandlerAdapter) {
        requestMappingHandlerAdapter.setWebBindingInitializer(new WebBindingInitializer() {
            @Override
            public void initBinder(WebDataBinder binder) {
                binder.registerCustomEditor(Date.class, new PropertyEditorSupport() {
                    @Override
                    public void setAsText(String text) {
                        // DateUtil.parse是hutool当中的方法
                        setValue(DateUtil.parse(text));
                    }
                });

                // 如果是字符串类型,就去除字符串的前后空格
                binder.registerCustomEditor(String.class,
                        new StringTrimmerEditor(true));
            }
        });
        return requestMappingHandlerAdapter;
    }
}
RequestMappingHandlerAdapter初始化
@Override
public void afterPropertiesSet() { //afterPropertiesSet是InitializingBean接口方法,在Bean对象初始化时调用
    // Do this first, it may add ResponseBody advice beans
    initControllerAdviceCache();
	//配置默认的参数解析器
    if (this.argumentResolvers == null) {
    List<HandlerMethodArgumentResolver> resolvers = getDefaultArgumentResolvers();
    this.argumentResolvers = new HandlerMethodArgumentResolverComposite().addResolvers(resolvers);
    }
    //配置默认的InitBinderArgumentResolvers解析器,如@InitBinder(单个handle)、@ControllerAdvice(全局handle)
    if (this.initBinderArgumentResolvers == null) {
    List<HandlerMethodArgumentResolver> resolvers = getDefaultInitBinderArgumentResolvers();
    this.initBinderArgumentResolvers = new HandlerMethodArgumentResolverComposite().addResolvers(resolvers);
    }
    //配置默认的返回值解析器
    if (this.returnValueHandlers == null) {
    List<HandlerMethodReturnValueHandler> handlers = getDefaultReturnValueHandlers();
    this.returnValueHandlers = new HandlerMethodReturnValueHandlerComposite().addHandlers(handlers);
    }
}
根据参数注解/类型寻找参数解析器

参数解析:以有@RequestMapping注解的HandlerAdapter(RequestMappingHandlerAdapter)为例

DispatchServlet.doDispatch–>ha.handle()–>AbstractHandlerMethodAdapter.handleInternal()–>RequestMappingHandlerAdapter.handleInternal()

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

		ModelAndView mav;
		checkRequest(request); //检查请求

		// 判断是否是同步session,默认是false
		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 {
			// 真正执行调用的处理请求方法
			mav = invokeHandlerMethod(request, response, handlerMethod);
		}

		if (!response.containsHeader(HEADER_CACHE_CONTROL)) {
			if (getSessionAttributesHandler(handlerMethod).hasSessionAttributes()) {
				applyCacheSeconds(response, this.cacheSecondsForSessionAttributeHandlers);
			}
			else {
				prepareResponse(response);
			}
		}

		return mav;
	}

// 真正执行调用的处理请求方法
mav = invokeHandlerMethod(request, response, handlerMethod);

@Nullable
protected ModelAndView invokeHandlerMethod(HttpServletRequest request,
      HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
	
   //封装Servlet请求
   ServletWebRequest webRequest = new ServletWebRequest(request, response);
   try {
       //根据方法请求获取数据绑定器,用于除了基本数据类型映射以外,处理日期等类型的映射
      WebDataBinderFactory binderFactory = getDataBinderFactory(handlerMethod);
      //创建Model工厂
      ModelFactory modelFactory = getModelFactory(handlerMethod, binderFactory);

      ServletInvocableHandlerMethod invocableMethod = createInvocableHandlerMethod(handlerMethod);
      //判断初始化参数解析器是否为空
       if (this.argumentResolvers != null) {
         //获取参数列表中各个参数的参数解析器(默认配置了27个)
         invocableMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers);
      }
      if (this.returnValueHandlers != null) {
         //获取返回值处理器(默认配置了14个)
         invocableMethod.setHandlerMethodReturnValueHandlers(this.returnValueHandlers);
      }
       //设置时间处理工厂
      invocableMethod.setDataBinderFactory(binderFactory);
      invocableMethod.setParameterNameDiscoverer(this.parameterNameDiscoverer);
		
      //创建ModelAndViewContainer,进行Model和View信息的存储
      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);
      }
	  //执行和处理方法,并将视图和数据封装进mavContainer中
      invocableMethod.invokeAndHandle(webRequest, mavContainer);
      if (asyncManager.isConcurrentHandlingStarted()) {
         return null;
      }
	  //获取ModelAndView
      return getModelAndView(mavContainer, modelFactory, webRequest);
   }
   finally {
      webRequest.requestCompleted();
   }
}

寻找参数解析器:

//执行上图invokeAndHandle(webRequest, mavContainer)
//		-->invokeAndHandle().invokeForRequest(webRequest, mavContainer, providedArgs)
//		-->invokeForRequest().getMethodArgumentValues(request, mavContainer, providedArgs)
//		-->getMethodArgumentValues()

//执行完getMethodArgumentValues()得到所有参数值

getMethodArgumentValues()获取方法参数值:

protected Object[] getMethodArgumentValues(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer,
			Object... providedArgs) throws Exception {
		//获取方法参数
		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.initParameterNameDiscovery(this.parameterNameDiscoverer);
			args[i] = findProvidedArgument(parameter, providedArgs);
			if (args[i] != null) {
				continue;
			}
			//判断是否有参数解析器可以解析这个参数 -->supports:支持
			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;
	}

通过参数类型,注解、名字来获取参数解析器

this.resolvers.supportsParameter(parameter)方法
	//将参数进行与参数解析器的适配:this.argumentResolvers默认的参数解析器类型,默认27个
	private HandlerMethodArgumentResolver getArgumentResolver(MethodParameter parameter) {
		HandlerMethodArgumentResolver result = this.argumentResolverCache.get(parameter);
		if (result == null) {
			for (HandlerMethodArgumentResolver resolver : this.argumentResolvers) {
				if (resolver.supportsParameter(parameter)) {
					result = resolver;
					this.argumentResolverCache.put(parameter, result);
					break;
				}
			}
		}
		return result;
	}

在这里插入图片描述

最终找到方法中每个参数的参数解析器进行解析。

执行方法

执行完getMethodArgumentValues()得到所有参数值args后。doInvoke(args)方法执行。

@Nullable
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);
}
方法执行完成:返回值处理器
  1. 在RequestMappingHandlerAdapter中设置了默认的返回器处理器(15个)

在这里插入图片描述

  1. 执行RequestMappingHandlerAdapter类中invokeHandlerMethod方法,会将默认参数解析器和返回值处理器添加。
if (this.argumentResolvers != null) {
	invocableMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers);
}
if (this.returnValueHandlers != null) {
	invocableMethod.setHandlerMethodReturnValueHandlers(this.returnValueHandlers);
}
  1. 然后会继续执行invokeHandlerMethod方法中的invokeAndHandle方法
public void invokeAndHandle(ServletWebRequest webRequest, ModelAndViewContainer mavContainer,
      Object... providedArgs) throws Exception {
	//处理请求,并返回返回值
   Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs);
   setResponseStatus(webRequest);
	//判断返回值是否为空
   if (returnValue == null) {
      if (isRequestNotModified(webRequest) || getResponseStatus() != null || mavContainer.isRequestHandled()) {
         disableContentCachingIfNecessary(webRequest);
         mavContainer.setRequestHandled(true);
         return;
      }
   }
   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;
   }
}
  1. this.returnValueHandlers.handleReturnValue(
    returnValue, getReturnValueType(returnValue), mavContainer, webRequest);
@Override
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);
}
  1. //将方法返回值和类型与处理器进行匹配,找到返回值处理器
    HandlerMethodReturnValueHandler handler = selectHandler(returnValue, returnType);

同样使用适配模式找到返回值处理器

@Nullable
private HandlerMethodReturnValueHandler selectHandler(@Nullable Object value, MethodParameter returnType) {
   boolean isAsyncValue = isAsyncReturnValue(value, returnType);
   for (HandlerMethodReturnValueHandler handler : this.returnValueHandlers) {
      if (isAsyncValue && !(handler instanceof AsyncHandlerMethodReturnValueHandler)) {
         continue;
      }
      if (handler.supportsReturnType(returnType)) {
         return handler;
      }
   }
   return null;
}

**常用的返回值处理器:**RequestResponseBodyMethodProcessor,ViewNameMethodReturnValueHandler,ModelAndViewMethodReturnValueHandler

返回值转换器
  1. 在RequestMappingHandlerAdapter中设置了四个默认返回值转换器 —>将返回值转为方法返回值类型
public RequestMappingHandlerAdapter() {
   this.messageConverters = new ArrayList<>(4);
   //添加负责读取二进制格式的数据和写出二进制格式的数据;
   this.messageConverters.add(new ByteArrayHttpMessageConverter());
   //添加负责读取字符串格式的数据和写出二进制格式的数据(当返回值是或者接受值是String类型时,是由这个处理)
   this.messageConverters.add(new StringHttpMessageConverter());
   if (!shouldIgnoreXml) {
      try {
      	 //添加负责读取和写入xml中javax.xml.transform.Source定义的数据
         this.messageConverters.add(new SourceHttpMessageConverter<>());
      }
      catch (Error err) {
         // Ignore when no TransformerFactory implementation is available
      }
   }
   //添加可以读取x-www-form-urlencoded参数的实现类(表单)
   this.messageConverters.add(new AllEncompassingFormHttpMessageConverter());
}

Json格式转换器(MappingJackson2XmlHttpMessageConverter):如果使用@ResposeBody注解,将返回值转换为Json格式数据。需要加入Json的依赖包jackson-core。SpringMVC会自动将返回值转换为Json格式数据。

找到返回值处理器后,处理返回值
handleReturnValue()
    --->handler.handleReturnValue(returnValue, returnType, mavContainer, webRequest); //处理返回值

handler == RequestResponseBodyMethodProcessor

这里以处理标注@ResponseBody注解的RequestResponseBodyMethodProcessor类举例。

@Override
public void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType,
    ModelAndViewContainer mavContainer, NativeWebRequest webRequest)
    throws IOException, HttpMediaTypeNotAcceptableException, HttpMessageNotWritableException {

	//设置请求已经处理完成。因为标注@ResponseBody不需要视图转发,不需要其他操作,所以直接设置为True。
    mavContainer.setRequestHandled(true);
    //将NativeWebRequest转为容易操作的ServletServerHttpRequest
    ServletServerHttpRequest inputMessage = createInputMessage(webRequest);
    ServletServerHttpResponse outputMessage = createOutputMessage(webRequest);

    //写入数据处理器
    writeWithMessageConverters(returnValue, returnType, inputMessage, outputMessage);
}

将数据写入页面

protected <T> void writeWithMessageConverters(@Nullable T value, MethodParameter returnType,
      ServletServerHttpRequest inputMessage, ServletServerHttpResponse outputMessage)
      throws IOException, HttpMediaTypeNotAcceptableException, HttpMessageNotWritableException {

   Object body;
   Class<?> valueType;
   Type targetType;

    //判断方法返回值是否属于String。value是方法返回值
    if (value instanceof CharSequence) {
        body = value.toString();
        valueType = String.class;
        targetType = String.class;
    }
    //不是String返回值类型
    else {
        body = value;
        //返回值类型
        valueType = getReturnValueType(body, returnType);
        //目标类型(方法的返回类型)
        targetType = GenericTypeResolver.resolveType(getGenericType(returnType), returnType.getContainingClass());
    }
    //判断是否是资源类型
    if (isResourceType(value, returnType)) {
        outputMessage.getHeaders().set(HttpHeaders.ACCEPT_RANGES, "bytes");
        if (value != null && inputMessage.getHeaders().getFirst(HttpHeaders.RANGE) != null &&
            outputMessage.getServletResponse().getStatus() == 200) {
            Resource resource = (Resource) value;
            try {
                List<HttpRange> httpRanges = inputMessage.getHeaders().getRange();
                outputMessage.getServletResponse().setStatus(HttpStatus.PARTIAL_CONTENT.value());
                body = HttpRange.toResourceRegions(httpRanges, resource);
                valueType = body.getClass();
                targetType = RESOURCE_REGION_LIST_TYPE;
            }
            catch (IllegalArgumentException ex) {
                outputMessage.getHeaders().set(HttpHeaders.CONTENT_RANGE, "bytes */" + resource.contentLength());
                outputMessage.getServletResponse().setStatus(HttpStatus.REQUESTED_RANGE_NOT_SATISFIABLE.value());
            }
        }
    }
	//添加前端浏览器媒体类型
   	MediaType selectedMediaType = null;
    //添加后端服务器媒体类型
   	MediaType contentType = outputMessage.getHeaders().getContentType();
    //是否是内容预设
    boolean isContentTypePreset = contentType != null && contentType.isConcrete();
    if (isContentTypePreset) {
      if (logger.isDebugEnabled()) {
         logger.debug("Found 'Content-Type:" + contentType + "' in response");
      }
      selectedMediaType = contentType;
    }
    else {
        //得到Request对象
        HttpServletRequest request = inputMessage.getServletRequest();
        //创建前端浏览器可接受的媒体类型对象
        List<MediaType> acceptableTypes;
        try {
            //获取前端浏览器传递的可接受的媒体类型
            acceptableTypes = getAcceptableMediaTypes(request);
        }
        catch (HttpMediaTypeNotAcceptableException ex) {
            int series = outputMessage.getServletResponse().getStatus() / 100;
            if (body == null || series == 4 || series == 5) {
                if (logger.isDebugEnabled()) {
                    logger.debug("Ignoring error response content (if any). " + ex);
                }
                return;
            }
            throw ex;
        }
        //获得后端服务器可生产的媒体类型
        List<MediaType> producibleTypes = getProducibleMediaTypes(request, valueType, targetType);

        if (body != null && producibleTypes.isEmpty()) {
            throw new HttpMessageNotWritableException(
                "No converter found for return value of type: " + valueType);
        }
        //添加可以使用的媒体类型
        List<MediaType> mediaTypesToUse = new ArrayList<>();
        for (MediaType requestedType : acceptableTypes) {
            for (MediaType producibleType : producibleTypes) {
                if (requestedType.isCompatibleWith(producibleType)) {
                    mediaTypesToUse.add(getMostSpecificMediaType(requestedType, producibleType));
                }
            }
        }
        if (mediaTypesToUse.isEmpty()) {
            if (body != null) {
                throw new HttpMediaTypeNotAcceptableException(producibleTypes);
            }
            if (logger.isDebugEnabled()) {
                logger.debug("No match for " + acceptableTypes + ", supported: " + producibleTypes);
            }
            return;
        }
		//根据特征排序
        MediaType.sortBySpecificityAndQuality(mediaTypesToUse);

        for (MediaType mediaType : mediaTypesToUse) {
            if (mediaType.isConcrete()) {
                selectedMediaType = mediaType;
                break;
            }
            else if (mediaType.isPresentIn(ALL_APPLICATION_MEDIA_TYPES)) {
                selectedMediaType = MediaType.APPLICATION_OCTET_STREAM;
                break;
            }
        }

        if (logger.isDebugEnabled()) {
            logger.debug("Using '" + selectedMediaType + "', given " +
                         acceptableTypes + " and supported " + producibleTypes);
        }
    }
	//找到可以使用的媒体类型后
    if (selectedMediaType != null) {
        selectedMediaType = selectedMediaType.removeQualityValue();
        //循环遍历查找哪个返回值处理器可以处理这种媒体类型
        for (HttpMessageConverter<?> converter : this.messageConverters) {
            //获得继承GenericHttpMessageConverter类的处理器
            GenericHttpMessageConverter genericConverter = (converter instanceof GenericHttpMessageConverter ?
                                                            (GenericHttpMessageConverter<?>) converter : null);
            //找到返回值处理器后
            if (genericConverter != null ?
                //将方法返回值转换为方法返回类型,这里使用的函数式接口调用生成body
                ((GenericHttpMessageConverter) converter).canWrite(targetType, valueType, selectedMediaType) :
                converter.canWrite(valueType, selectedMediaType)) {

                body = getAdvice().beforeBodyWrite(body, returnType, selectedMediaType,
                                                   (Class<? extends HttpMessageConverter<?>>) converter.getClass(),
                                                   inputMessage, outputMessage);
                //判断转换后的数据是否为空
                if (body != null) {
                    Object theBody = body;
                    LogFormatUtils.traceDebug(logger, traceOn ->
                                              "Writing [" + LogFormatUtils.formatValue(theBody, !traceOn) + "]");
                    addContentDispositionHeader(inputMessage, outputMessage);
                    if (genericConverter != null) {
                        //将数据写回页面
                        genericConverter.write(body, targetType, selectedMediaType, outputMessage);
                    }
                    else {
                        ((HttpMessageConverter) converter).write(body, selectedMediaType, outputMessage);
                    }
                }
                else {
                    if (logger.isDebugEnabled()) {
                        logger.debug("Nothing to write: null body");
                    }
                }
                //将数据写回页面后,返回
                return;
            }
        }
    }

    if (body != null) {
        Set<MediaType> producibleMediaTypes =
            (Set<MediaType>) inputMessage.getServletRequest()
            .getAttribute(HandlerMapping.PRODUCIBLE_MEDIA_TYPES_ATTRIBUTE);

        if (isContentTypePreset || !CollectionUtils.isEmpty(producibleMediaTypes)) {
            throw new HttpMessageNotWritableException(
                "No converter for [" + valueType + "] with preset Content-Type '" + contentType + "'");
        }
        throw new HttpMediaTypeNotAcceptableException(getSupportedMediaTypes(body.getClass()));
    }
}
需要视图解析器处理请求(没有标注@ResponseBody注解的):

DispatchServlet通过适配到的HandlerAdapter执行完handle方法,返回封装好的视图和数据ModelAndView,通过后续processDispatchResult方法,处理视图,进行页面跳转和渲染.

DispatchServlet-->mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
   -->RequestMappingHandlerAdapter类
        执行完invokeHandlerMethod().invokeAndHandle()后
        返回getModelAndView(mavContainer, modelFactory, webRequest);
private ModelAndView getModelAndView(ModelAndViewContainer mavContainer,
      ModelFactory modelFactory, NativeWebRequest webRequest) throws Exception {

    //如果请求类中有@SessionAttributes注解,会将Session中数据放入mavContainer
    modelFactory.updateModel(webRequest, mavContainer);
    //判断请求是否处理完成了,RequestResponseBodyMethodProcessor处理时会在写页面数据之前设置为true,用来此处判断,没有视图
    if (mavContainer.isRequestHandled()) {
        return null;
    }
    //获取Model数据
    ModelMap model = mavContainer.getModel();
    //将视图名,Model数据封装为一个ModelAndView
    ModelAndView mav = new ModelAndView(mavContainer.getViewName(), model, mavContainer.getStatus());
    //判断是否是视图转发
    if (!mavContainer.isViewReference()) {
        mav.setView((View) mavContainer.getView());
    }
    //判断是否是重定向
    if (model instanceof RedirectAttributes) {
        Map<String, ?> flashAttributes = ((RedirectAttributes) model).getFlashAttributes();
        HttpServletRequest request = webRequest.getNativeRequest(HttpServletRequest.class);
        if (request != null) {
            RequestContextUtils.getOutputFlashMap(request).putAll(flashAttributes);
        }
    }
    //将封装好的视图进行返回到DispatchServlet进行处理
    return mav;
}

寻找视图解析器:DispatchServlet.resolveViewName()

找到视图解析器,SpringMVC默认设置了一个视图解析器InternalResourceViewResolver,处理JSP页面

@Nullable
protected View resolveViewName(String viewName, @Nullable Map<String, Object> model,
      Locale locale, HttpServletRequest request) throws Exception {

    if (this.viewResolvers != null) {
        for (ViewResolver viewResolver : this.viewResolvers) {
            //找到适配的视图解析器,解析视图名找到视图,默认只有一个处理JSP页面的InternalResourceViewResolver
            View view = viewResolver.resolveViewName(viewName, locale);
            if (view != null) {
                return view;
            }
        }
    }
    return null;
}

视图解析器解析视图:InternalResourceViewResolver调用父类中AbstractCachingViewResolver.resolveViewName()

public View resolveViewName(String viewName, Locale locale) throws Exception {
   //查看是否有缓存
   if (!isCache()) {
      return createView(viewName, locale);
   }
   else {
   	  //获取缓存中的View
      Object cacheKey = getCacheKey(viewName, locale);
      View view = this.viewAccessCache.get(cacheKey);
      //如果缓存中没有view,创建View
      if (view == null) {
         synchronized (this.viewCreationCache) {
            view = this.viewCreationCache.get(cacheKey);
            if (view == null) {
               //根据视图名创建视图
               view = createView(viewName, locale);
               //创建失败,设置一个未解决的视图
               if (view == null && this.cacheUnresolved) {
                  view = UNRESOLVED_VIEW;
               }
               //将创建的视图放入缓存中
               if (view != null && this.cacheFilter.filter(view, viewName, locale)) {
                  this.viewAccessCache.put(cacheKey, view);
                  this.viewCreationCache.put(cacheKey, view);
               }
            }
         }
      }
      else {
         if (logger.isTraceEnabled()) {
            logger.trace(formatKey(cacheKey) + "served from cache");
         }
      }
      //返回创建的视图
      return (view != UNRESOLVED_VIEW ? view : null);
   }
}

创建视图:UrlBasedViewResolver

@Override
protected View createView(String viewName, Locale locale) throws Exception {
    // If this resolver is not supposed to handle the given view,
    // return null to pass on to the next resolver in the chain.
    if (!canHandle(viewName, locale)) {
        return null;
    }
    //判断是否是重定向,如果是重定向创建RedirectView视图
    if (viewName.startsWith(REDIRECT_URL_PREFIX)) {
        String redirectUrl = viewName.substring(REDIRECT_URL_PREFIX.length());
        RedirectView view = new RedirectView(redirectUrl,
                                             isRedirectContextRelative(), isRedirectHttp10Compatible());
        String[] hosts = getRedirectHosts();
        if (hosts != null) {
            view.setHosts(hosts);
        }
        return applyLifecycleMethods(REDIRECT_URL_PREFIX, view);
    }

    // 判断是否是转发,如果是转发创建InternalResourceView视图
    if (viewName.startsWith(FORWARD_URL_PREFIX)) {
        String forwardUrl = viewName.substring(FORWARD_URL_PREFIX.length());
        InternalResourceView view = new InternalResourceView(forwardUrl);
        return applyLifecycleMethods(FORWARD_URL_PREFIX, view);
    }

    // 如果视图名前没标注,调用父类AbstractCachingViewResolver中创建视图方法
    return super.createView(viewName, locale);
}

父类AbstractCachingViewResolver中创建视图方法

protected View createView(String viewName, Locale locale) throws Exception {
   //加载视图,loadView是View接口中的方法
   return loadView(viewName, locale);
}

子类(InternalResourceViewResolver)实现loadView接口方法:UrlBasedViewResolver

@Override
protected View loadView(String viewName, Locale locale) throws Exception {
   //构建View,处理jsp页面跳转到InternalResourceViewResolver中的buildView方法,创建
   AbstractUrlBasedView view = buildView(viewName);
   View result = applyLifecycleMethods(viewName, view);
   //返回View
   return (view.checkResource(locale) ? result : null);
}

创建处理JSP的View:InternalResourceViewResolver.buildView —>InternalResourceView

@Override
protected AbstractUrlBasedView buildView(String viewName) throws Exception {
    //创建处理JSP的InternalResourceView
   InternalResourceView view = (InternalResourceView) super.buildView(viewName);
   if (this.alwaysInclude != null) {
      view.setAlwaysInclude(this.alwaysInclude);
   }
   view.setPreventDispatchLoop(true);
    //返回视图
   return view;
}

将视图返回到DispatchServlet后进行结果处理

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.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..
    	mappedHandler.triggerAfterCompletion(request, response, null);
    }
}

视图渲染

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) {
        // 解析视图名
        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) {
            request.setAttribute(View.RESPONSE_STATUS_ATTRIBUTE, mv.getStatus());
            response.setStatus(mv.getStatus().value());
        }
        //渲染当前View页面
        view.render(mv.getModelInternal(), request, response);
    }
    catch (Exception ex) {
        if (logger.isDebugEnabled()) {
            logger.debug("Error rendering view [" + view + "]", ex);
        }
        throw ex;
    }
}

渲染视图:DispatchServlet.render() —>view.render() —>Abstract.renderMergedOutputModel()—>InternalResourceView.renderMergedOutputModel()

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

   //将模型对象公开为请求属性
   exposeModelAsRequestAttributes(model, request);

   // 如果有的话,将帮助程序公开为请求属性。
   exposeHelpers(request);

   // 确定请求调度程序的路径。
   String dispatcherPath = prepareForRendering(request, response);

   // 获取目标资源(通常是JSP)的RequestDispatcher
   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!");
   }

   //得到路径和RequestDispatcher请求后,就不是SpringMvc中代码,使用的Tomcat中Servlet中代码进行跳转
    
   // 如果已经包含或响应已经提交,则执行include,否则执行forward。
   if (useInclude(request, response)) {
      response.setContentType(getContentType());
      if (logger.isDebugEnabled()) {
         logger.debug("Including [" + getUrl() + "]");
      }
      rd.include(request, response);
   }

   else {
      // 注意:被转发的资源应该决定内容类型本身
      if (logger.isDebugEnabled()) {
         logger.debug("Forwarding to [" + getUrl() + "]");
      }
      rd.forward(request, response);
   }
}

处理请求完成

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值