简单分析Spring MVC源码

简单分析Spring MVC源码

一、DispatcherServlet的继承关系

二、DispatcherServlet收到请求的一个大致流程

三、测试代码
1、springmvc.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:mvc="http://www.springframework.org/schema/mvc"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd">

    <!-- 开启组件扫描 -->
    <context:component-scan base-package="cn.ilqjx"/>

    <!-- 配置视图解析器 -->
    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/pages/"/>
        <property name="suffix" value=".jsp"/>
    </bean>
</beans>
2、success.jsp
<%@ page contentType="text/html; charset=UTF-8" language="java" %>
<html>
<head>
    <title>success</title>
</head>
<body>
<%
    System.out.println("调用目标页面 success.jsp");
%>
</body>
</html>
3、HelloController
@Controller
public class HelloController {

	@RequestMapping("/hello")
	public String hello() {
	    System.out.println("调用目标方法 hello()");
	    return "success";
	}
}
四、确定目标方法和目标页面的调用位置
1、DispatcherServlet#doDispatch源码
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;

			// Determine handler for the current request.
			mappedHandler = getHandler(processedRequest);
			if (mappedHandler == null || mappedHandler.getHandler() == null) {
				noHandlerFound(processedRequest, response);
				return;
			}

			// Determine handler adapter for the current request.
			HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());

			// Process last-modified header, if supported by the handler.
			String method = request.getMethod();
			boolean isGet = "GET".equals(method);
			if (isGet || "HEAD".equals(method)) {
				long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
				if (logger.isDebugEnabled()) {
					String requestUri = urlPathHelper.getRequestUri(request);
					logger.debug("Last-Modified value for [" + requestUri + "] is: " + lastModified);
				}
				if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
					return;
				}
			}

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

			try {
				// Actually invoke the handler.
				// 调用处理器的方法
				mv = ha.handle(processedRequest, response, mappedHandler.getHandler()); 
			}
			finally {
				if (asyncManager.isConcurrentHandlingStarted()) {
					return;
				}
			}

			applyDefaultViewName(request, mv);
			mappedHandler.applyPostHandle(processedRequest, response, mv);
		}
		catch (Exception ex) {
			dispatchException = ex;
		}
		// 转发到目标页面
		processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
	}
	catch (Exception ex) {
		triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
	}
	catch (Error err) {
		triggerAfterCompletionWithError(processedRequest, response, mappedHandler, err);
	}
	finally {
		if (asyncManager.isConcurrentHandlingStarted()) {
			// Instead of postHandle and afterCompletion
			mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
			return;
		}
		// Clean up any resources used by a multipart request.
		if (multipartRequestParsed) {
			cleanupMultipart(processedRequest);
		}
	}
}
2、目标方法和目标页面的调用位置
// 调用处理器的方法
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

// 转发到目标页面
processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
五、分析DispatcherServlet#doDispatch
1、分析
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;

			// Determine handler for the current request.
			// 确定当前请求的处理器
			/*
			 mappedHandler = {HandlerExecutionChain@5606}
			 	 // HelloController 处理器
				 handler = {HelloController@5946}
				 interceptors = {HandlerInterceptor[1]@5947} 
				 interceptorList = {ArrayList@5948}  size = 1
				 interceptorIndex = 0
			*/
			mappedHandler = getHandler(processedRequest);
			// 如果找不到处理器,就会抛异常或404
			if (mappedHandler == null || mappedHandler.getHandler() == null) {
				noHandlerFound(processedRequest, response);
				return;
			}

			// Determine handler adapter for the current request.
			// 确定当前请求的处理器适配器
			// ha: AnnotationMethodHandlerAdapter
			HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());

			// Process last-modified header, if supported by the handler.
			String method = request.getMethod();
			boolean isGet = "GET".equals(method);
			if (isGet || "HEAD".equals(method)) {
				long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
				if (logger.isDebugEnabled()) {
					String requestUri = urlPathHelper.getRequestUri(request);
					logger.debug("Last-Modified value for [" + requestUri + "] is: " + lastModified);
				}
				if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
					return;
				}
			}

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

			try {
				// Actually invoke the handler.
				// 适配器执行目标方法并将返回值作为视图名封装到 ModelAndView 中
				// 无论目标方法怎么写,最终适配器执行完目标方法后,都会将执行后的信息封装成 ModelAndView
				/*
				 mv = {ModelAndView@5950}
				 	 // 视图名
	 				 view = "success"
					 model = {ModelMap@5957}  size = 0
					 cleared = false
				*/
				mv = ha.handle(processedRequest, response, mappedHandler.getHandler()); 
			}
			finally {
				if (asyncManager.isConcurrentHandlingStarted()) {
					return;
				}
			}

			// 如果没有视图名,设置一个默认的视图名。比如:目标方法的返回值为 void,视图名为请求地址
			applyDefaultViewName(request, mv);
			mappedHandler.applyPostHandle(processedRequest, response, mv);
		}
		catch (Exception ex) {
			dispatchException = ex;
		}
		// 根据目标方法执行完后封装的 ModelAndView 转发到目标页面,而且 ModelAndView 中的数据可以从请求域中获取。
		processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
	}
	catch (Exception ex) {
		triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
	}
	catch (Error err) {
		triggerAfterCompletionWithError(processedRequest, response, mappedHandler, err);
	}
	finally {
		if (asyncManager.isConcurrentHandlingStarted()) {
			// Instead of postHandle and afterCompletion
			mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
			return;
		}
		// Clean up any resources used by a multipart request.
		if (multipartRequestParsed) {
			cleanupMultipart(processedRequest);
		}
	}
}
2、小总结

DispatcherServlet收到请求调用doDispatch()方法进行处理
(1)、getHandler():根据当前请求地址找到能处理这个请求的目标处理器
根据当前请求在 HandlerMapping 中找到这个请求的映射信息,获取到目标处理器。
(2)、getHandlerAdapter():根据当前处理器获取到能执行这个处理器方法的适配器
根据当前处理器,获取到相应的 HandlerAdapter。
(3)、handle():使用适配器执行目标方法并返回一个 ModelAndView 对象
(4)、processDispatchResult():根据 ModelAndView 的信息转发到具体的页面,并且可以从请求域中取出 ModelAndView 中的模型数据

六、细节分析
1、getHandler()细节:如何根据当前请求找到对应的处理器
1.1、getHandler()源码

getHandler()返回目标处理器的执行链

mappedHandler = getHandler(processedRequest);
protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
	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;
}
1.2、分析getHandler()

HandlerMapping:处理器映射,保存了每一个处理器能够处理哪些请求的映射信息

BeanNameUrlHandlerMapping:处理 xml 配置的
DefaultAnnotationHandlerMapping:处理注解的

handlerMap:ioc 容器启动创建 Controller 对象的时候扫描每个处理器都能处理什么请求,保存在 handlerMap 属性中。下一次请求过来,就会查看哪个 HandlerMapping 中有请求映射信息。

2、getHandlerAdapter()细节:如何根据当前处理器找到相应的适配器
2.1、getHandlerAdapter()源码
protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
	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");
}
2.2、分析getHandlerAdapter()

AnnotationMethodHandlerAdapter:解析注解方法的适配器

七、Spring MVC的九大组件

Spring MVC在工作的时候,关键位置都是由这些组件完成的。
共同点:九大组件都是接口,接口就是规范,提供了非常强大的扩展性。

/** 文件上传解析器 */
private MultipartResolver multipartResolver;

/** 区域信息解析器(与国际化相关) */
private LocaleResolver localeResolver;

/** 主题解析器(强大的主题效果更换) */
private ThemeResolver themeResolver;

/** Handler 映射信息 */
private List<HandlerMapping> handlerMappings;

/** Handler 的适配器 */
private List<HandlerAdapter> handlerAdapters;

/** 异常解析器(Spring MVC强大的异常解析功能) */
private List<HandlerExceptionResolver> handlerExceptionResolvers;

/** 从 request 中获取视图名 */
private RequestToViewNameTranslator viewNameTranslator;

/** FlashMap + Manager:Spring MVC中允许重定向携带数据的功能 */
private FlashMapManager flashMapManager;

/** 视图解析器 */
private List<ViewResolver> viewResolvers;
1、九大组件初始化的地方
protected void initStrategies(ApplicationContext context) {
	initMultipartResolver(context);
	initLocaleResolver(context);
	initThemeResolver(context);
	initHandlerMappings(context);
	initHandlerAdapters(context);
	initHandlerExceptionResolvers(context);
	initRequestToViewNameTranslator(context);
	initViewResolvers(context);
	initFlashMapManager(context);
}
2、分析九大组件初始化方法之 initLocaleResolver(),其他类似

有些组件在容器中是使用 id 进行查找的,有些组件是使用类型进行查找的。
去容器中查找这个组件,如果没找到就使用默认的配置。

private void initLocaleResolver(ApplicationContext context) {
	try {
		// public static final String LOCALE_RESOLVER_BEAN_NAME = "localeResolver";
		// 根据 id 从 ioc 容器中获取
		this.localeResolver = context.getBean(LOCALE_RESOLVER_BEAN_NAME, LocaleResolver.class);
		if (logger.isDebugEnabled()) {
			logger.debug("Using LocaleResolver [" + this.localeResolver + "]");
		}
	}
	catch (NoSuchBeanDefinitionException ex) {
		// We need to use the default.
		// 如果没获取到,使用默认配置
		this.localeResolver = getDefaultStrategy(context, LocaleResolver.class);
		if (logger.isDebugEnabled()) {
			logger.debug("Unable to locate LocaleResolver with name '" + LOCALE_RESOLVER_BEAN_NAME +
					"': using default [" + this.localeResolver + "]");
		}
	}
}
3、默认配置
/**
 * Name of the class path resource (relative to the DispatcherServlet class)
 * that defines DispatcherServlet's default strategy names.
 */
private static final String DEFAULT_STRATEGIES_PATH = "DispatcherServlet.properties";

4、可以在web.xml中修改DispatcherServlet某些属性的默认配置
/** Detect all HandlerMappings or just expect "handlerMapping" bean? */
private boolean detectAllHandlerMappings = true;
<servlet>
    <servlet-name>springmvc</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <init-param>
        <param-name>detectAllHandlerMappings</param-name>
        <param-value>false</param-value>
    </init-param>
</servlet>
<servlet-mapping>
    <servlet-name>springmvc</servlet-name>
    <url-pattern>/</url-pattern>
</servlet-mapping>
八、执行目标方法的细节
// 执行目标方法
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
			throws Exception {

	Class<?> clazz = ClassUtils.getUserClass(handler);
	Boolean annotatedWithSessionAttributes = this.sessionAnnotatedClassesCache.get(clazz);
	if (annotatedWithSessionAttributes == null) {
		annotatedWithSessionAttributes = (AnnotationUtils.findAnnotation(clazz, SessionAttributes.class) != null);
		this.sessionAnnotatedClassesCache.put(clazz, annotatedWithSessionAttributes);
	}

	if (annotatedWithSessionAttributes) {
		// Always prevent caching in case of session attribute management.
		checkAndPrepare(request, response, this.cacheSecondsForSessionAttributeHandlers, true);
		// Prepare cached set of session attributes names.
	}
	else {
		// Uses configured default cacheSeconds setting.
		checkAndPrepare(request, response, true);
	}

	// 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) {
				return invokeHandlerMethod(request, response, handler);
			}
		}
	}

	// 执行目标方法
	return invokeHandlerMethod(request, response, handler);
}

protected ModelAndView invokeHandlerMethod(HttpServletRequest request, HttpServletResponse response, Object handler)
			throws Exception {

	// 获取方法解析器
	ServletHandlerMethodResolver methodResolver = getMethodResolver(handler);
	// 方法解析器根据当前请求地址找到目标方法
	// handlerMethod: public java.lang.String cn.ilqjx.controller.HelloController.hello()
	Method handlerMethod = methodResolver.resolveHandlerMethod(request);
	// 创建方法执行器
	ServletHandlerMethodInvoker methodInvoker = new ServletHandlerMethodInvoker(methodResolver);
	// 对原生的 request 和 response 进行包装
	ServletWebRequest webRequest = new ServletWebRequest(request, response);
	// 创建隐含模型
	ExtendedModelMap implicitModel = new BindingAwareModelMap();

	// 真正执行目标方法;目标方法利用反射执行期间确定参数值,提前执行标了 @ModelAttribute 注解的方法等所有的操作都在这个方法中
	Object result = methodInvoker.invokeHandlerMethod(handlerMethod, handler, webRequest, implicitModel);
	ModelAndView mav =
			methodInvoker.getModelAndView(handlerMethod, handler.getClass(), result, implicitModel, webRequest);
	methodInvoker.updateModelAttributes(handler, (mav != null ? mav.getModel() : null), implicitModel, webRequest);
	return mav;
}
1、测试代码
1.1、form表单
<form action="/springmvc/updateBook" method="post">
    书名:<input type="text" name="bookName"/> <br/>
    作者:<input type="text" name="author"/> <br/>
    <input type="submit" value="更新图书"/>
</form>
1.2、BookController

为了观察如何给目标方法的参数赋值,所以更换测试代码。

@Controller
public class BookController {

    @RequestMapping("/updateBook")
    public String updateBook(@RequestParam("author") String author, Map<String, Object> map,
                             HttpServletRequest request, @ModelAttribute("book") Book book) {
        System.out.println("更新后的 book: " + book);
        System.out.println("调用了 updateBook() 方法");
        return "success";
    }

    @ModelAttribute
    public void init(Map<String, Object> map) {
        Book book = new Book("如何让富婆爱上我", "无名");
        map.put("book", book);
        System.out.println("调用了 init() 方法");
    }
}
2、执行目标方法
// 真正执行目标方法
Object result = methodInvoker.invokeHandlerMethod(handlerMethod, handler, webRequest, implicitModel);
public final Object invokeHandlerMethod(Method handlerMethod, Object handler,
			NativeWebRequest webRequest, ExtendedModelMap implicitModel) throws Exception {

	// 获取到要要执行的处理器方法
	// public java.lang.String 	cn.ilqjx.controller.BookController.updateBook(java.lang.String,java.util.Map,javax.servlet.http.HttpServletRequest,cn.ilqjx.pojo.Book)
	Method handlerMethodToInvoke = BridgeMethodResolver.findBridgedMethod(handlerMethod);
	try {
		boolean debug = logger.isDebugEnabled();
		for (String attrName : this.methodResolver.getActualSessionAttributeNames()) {
			Object attrValue = this.sessionAttributeStore.retrieveAttribute(webRequest, attrName);
			if (attrValue != null) {
				implicitModel.addAttribute(attrName, attrValue);
			}
		}
		// 获取标注了 @ModelAttribute 注解的所有方法
		for (Method attributeMethod : this.methodResolver.getModelAttributeMethods()) {
			// 我们的测试代码中只有 init() 方法标注了 @ModelAttribute 注解
			// public void cn.ilqjx.controller.BookController.init(java.util.Map)
			Method attributeMethodToInvoke = BridgeMethodResolver.findBridgedMethod(attributeMethod);
			// 确定标注了@ModelAttribute注解的方法执行时要使用的每一个参数的值(见2.1)
			Object[] args = resolveHandlerArguments(attributeMethodToInvoke, handler, webRequest, implicitModel);
			if (debug) {
				logger.debug("Invoking model attribute method: " + attributeMethodToInvoke);
			}
			// 分析 attrName 的值(见2.4)
			String attrName = AnnotationUtils.findAnnotation(attributeMethod, ModelAttribute.class).value();
			if (!"".equals(attrName) && implicitModel.containsAttribute(attrName)) {
				continue;
			}
			// 设置目标方法是可访问的
			ReflectionUtils.makeAccessible(attributeMethodToInvoke);
			// 执行标注了 @ModelAttribute 注解的方法(先于目标方法运行)
			Object attrValue = attributeMethodToInvoke.invoke(handler, args);
			if ("".equals(attrName)) {
				Class<?> resolvedType = GenericTypeResolver.resolveReturnType(attributeMethodToInvoke, handler.getClass());
				attrName = Conventions.getVariableNameForReturnType(attributeMethodToInvoke, resolvedType, attrValue);
			}
			// @ModelAttribute注解的另一个作用(见2.5)
			// 把提前运行的标注了@ModelAttribute注解的方法的返回值放在隐含模型中
			if (!implicitModel.containsAttribute(attrName)) {
				implicitModel.addAttribute(attrName, attrValue);
			}
		}
		// 确定目标方法执行时要使用的每一个参数的值(见2.6,和2.1是同一个方法,在详细分析一下)
		Object[] args = resolveHandlerArguments(handlerMethodToInvoke, handler, webRequest, implicitModel);
		if (debug) {
			logger.debug("Invoking request handler method: " + handlerMethodToInvoke);
		}
		// 设置为可访问的
		ReflectionUtils.makeAccessible(handlerMethodToInvoke);
		// 执行目标方法
		return handlerMethodToInvoke.invoke(handler, args);
	}
	catch (IllegalStateException ex) {
		// Internal assertion failed (e.g. invalid signature):
		// throw exception with full handler method context...
		throw new HandlerMethodInvocationException(handlerMethodToInvoke, ex);
	}
	catch (InvocationTargetException ex) {
		// User-defined @ModelAttribute/@InitBinder/@RequestMapping method threw an exception...
		ReflectionUtils.rethrowException(ex.getTargetException());
		return null;
	}
}
2.1、确定方法执行时要使用的每一个参数的值

下面的分析参照此测试代码

@ModelAttribute
public void init(Map<String, Object> map) {
    Book book = new Book("如何让富婆爱上我", "无名");
    map.put("book", book);
    System.out.println("调用了 init() 方法");
}
// 确定方法执行时要使用的每一个参数的值
Object[] args = resolveHandlerArguments(attributeMethodToInvoke, handler, webRequest, implicitModel);
private Object[] resolveHandlerArguments(Method handlerMethod, Object handler,
			NativeWebRequest webRequest, ExtendedModelMap implicitModel) throws Exception {

	Class<?>[] paramTypes = handlerMethod.getParameterTypes();
	// 创建了一个长度和参数个数一样多的数组,会用来保存每一个参数的值
	Object[] args = new Object[paramTypes.length];

	// 遍历方法的所有参数
	for (int i = 0; i < args.length; i++) {
		MethodParameter methodParam = new MethodParameter(handlerMethod, i);
		methodParam.initParameterNameDiscovery(this.parameterNameDiscoverer);
		GenericTypeResolver.resolveParameterType(methodParam, handler.getClass());
		String paramName = null;
		String headerName = null;
		boolean requestBodyFound = false;
		String cookieName = null;
		String pathVarName = null;
		String attrName = null;
		boolean required = false;
		String defaultValue = null;
		boolean validate = false;
		Object[] validationHints = null;
		int annotationsFound = 0;
		// 获取方法这个参数的所有注解
		Annotation[] paramAnns = methodParam.getParameterAnnotations();

		// 如果有注解就解析并保存注解的信息
		for (Annotation paramAnn : paramAnns) {
			if (RequestParam.class.isInstance(paramAnn)) {
				RequestParam requestParam = (RequestParam) paramAnn;
				paramName = requestParam.value();
				required = requestParam.required();
				defaultValue = parseDefaultValueAttribute(requestParam.defaultValue());
				annotationsFound++;
			}
			else if (RequestHeader.class.isInstance(paramAnn)) {
				RequestHeader requestHeader = (RequestHeader) paramAnn;
				headerName = requestHeader.value();
				required = requestHeader.required();
				defaultValue = parseDefaultValueAttribute(requestHeader.defaultValue());
				annotationsFound++;
			}
			else if (RequestBody.class.isInstance(paramAnn)) {
				requestBodyFound = true;
				annotationsFound++;
			}
			else if (CookieValue.class.isInstance(paramAnn)) {
				CookieValue cookieValue = (CookieValue) paramAnn;
				cookieName = cookieValue.value();
				required = cookieValue.required();
				defaultValue = parseDefaultValueAttribute(cookieValue.defaultValue());
				annotationsFound++;
			}
			else if (PathVariable.class.isInstance(paramAnn)) {
				PathVariable pathVar = (PathVariable) paramAnn;
				pathVarName = pathVar.value();
				annotationsFound++;
			}
			else if (ModelAttribute.class.isInstance(paramAnn)) {
				ModelAttribute attr = (ModelAttribute) paramAnn;
				attrName = attr.value();
				annotationsFound++;
			}
			else if (Value.class.isInstance(paramAnn)) {
				defaultValue = ((Value) paramAnn).value();
			}
			else if (paramAnn.annotationType().getSimpleName().startsWith("Valid")) {
				validate = true;
				Object value = AnnotationUtils.getValue(paramAnn);
				validationHints = (value instanceof Object[] ? (Object[]) value : new Object[] {value});
			}
		}

		if (annotationsFound > 1) {
			throw new IllegalStateException("Handler parameter annotations are exclusive choices - " +
					"do not specify more than one such annotation on the same parameter: " + handlerMethod);
		}

		// 没有注解的情况
		if (annotationsFound == 0) {
			// 解析普通参数(见2.2)
			Object argValue = resolveCommonArgument(methodParam, webRequest);
			if (argValue != WebArgumentResolver.UNRESOLVED) {
				args[i] = argValue;
			}
			else if (defaultValue != null) {
				args[i] = resolveDefaultValue(defaultValue);
			}
			else {
				// 获取参数类型
				Class<?> paramType = methodParam.getParameterType();
				// 如果是 Model 类型或者是 Map类型,则将之前创建的隐含模型赋值给这个参数
				if (Model.class.isAssignableFrom(paramType) || Map.class.isAssignableFrom(paramType)) {
					if (!paramType.isAssignableFrom(implicitModel.getClass())) {
						throw new IllegalStateException("Argument [" + paramType.getSimpleName() + "] is of type " +
								"Model or Map but is not assignable from the actual model. You may need to switch " +
								"newer MVC infrastructure classes to use this argument.");
					}
					// 将隐含模型赋值给这个参数
					args[i] = implicitModel;
				}
				else if (SessionStatus.class.isAssignableFrom(paramType)) {
					args[i] = this.sessionStatus;
				}
				else if (HttpEntity.class.isAssignableFrom(paramType)) {
					args[i] = resolveHttpEntityRequest(methodParam, webRequest);
				}
				else if (Errors.class.isAssignableFrom(paramType)) {
					throw new IllegalStateException("Errors/BindingResult argument declared " +
							"without preceding model attribute. Check your handler method signature!");
				}
				else if (BeanUtils.isSimpleProperty(paramType)) {
					paramName = "";
				}
				else {
					attrName = "";
				}
			}
		}

		if (paramName != null) {
			args[i] = resolveRequestParam(paramName, required, defaultValue, methodParam, webRequest, handler);
		}
		else if (headerName != null) {
			args[i] = resolveRequestHeader(headerName, required, defaultValue, methodParam, webRequest, handler);
		}
		else if (requestBodyFound) {
			args[i] = resolveRequestBody(methodParam, webRequest, handler);
		}
		else if (cookieName != null) {
			args[i] = resolveCookieValue(cookieName, required, defaultValue, methodParam, webRequest, handler);
		}
		else if (pathVarName != null) {
			args[i] = resolvePathVariable(pathVarName, methodParam, webRequest, handler);
		}
		else if (attrName != null) {
			WebDataBinder binder =
					resolveModelAttribute(attrName, methodParam, implicitModel, webRequest, handler);
			boolean assignBindingResult = (args.length > i + 1 && Errors.class.isAssignableFrom(paramTypes[i + 1]));
			if (binder.getTarget() != null) {
				doBind(binder, webRequest, validate, validationHints, !assignBindingResult);
			}
			args[i] = binder.getTarget();
			if (assignBindingResult) {
				args[i + 1] = binder.getBindingResult();
				i++;
			}
			implicitModel.putAll(binder.getBindingResult().getModel());
		}
	}

	return args;
}
2.2、解析普通参数

如果没有注解,先看是否是普通参数,确定当前的参数是否是原生API。

// 解析普通参数
Object argValue = resolveCommonArgument(methodParam, webRequest);
protected Object resolveCommonArgument(MethodParameter methodParameter, NativeWebRequest webRequest)
			throws Exception {

	// Invoke custom argument resolvers if present...
	if (this.customArgumentResolvers != null) {
		for (WebArgumentResolver argumentResolver : this.customArgumentResolvers) {
			Object value = argumentResolver.resolveArgument(methodParameter, webRequest);
			if (value != WebArgumentResolver.UNRESOLVED) {
				return value;
			}
		}
	}

	// Resolution of standard parameter types...
	Class<?> paramType = methodParameter.getParameterType();
	// 确定当前的参数是否是原生API(见2.3)
	Object value = resolveStandardArgument(paramType, webRequest);
	if (value != WebArgumentResolver.UNRESOLVED && !ClassUtils.isAssignableValue(paramType, value)) {
		throw new IllegalStateException("Standard argument type [" + paramType.getName() +
				"] resolved to incompatible value of type [" + (value != null ? value.getClass() : null) +
				"]. Consider declaring the argument type in a less specific fashion.");
	}
	return value;
}
2.3、确定当前的参数是否是原生API
// 确定当前的参数是否是原生API
Object value = resolveStandardArgument(paramType, webRequest);
protected Object resolveStandardArgument(Class<?> parameterType, NativeWebRequest webRequest) throws Exception {
	HttpServletRequest request = webRequest.getNativeRequest(HttpServletRequest.class);
	HttpServletResponse response = webRequest.getNativeResponse(HttpServletResponse.class);

	if (ServletRequest.class.isAssignableFrom(parameterType) ||
			MultipartRequest.class.isAssignableFrom(parameterType)) {
		Object nativeRequest = webRequest.getNativeRequest(parameterType);
		if (nativeRequest == null) {
			throw new IllegalStateException(
					"Current request is not of type [" + parameterType.getName() + "]: " + request);
		}
		return nativeRequest;
	}
	else if (ServletResponse.class.isAssignableFrom(parameterType)) {
		this.responseArgumentUsed = true;
		Object nativeResponse = webRequest.getNativeResponse(parameterType);
		if (nativeResponse == null) {
			throw new IllegalStateException(
					"Current response is not of type [" + parameterType.getName() + "]: " + response);
		}
		return nativeResponse;
	}
	else if (HttpSession.class.isAssignableFrom(parameterType)) {
		return request.getSession();
	}
	else if (Principal.class.isAssignableFrom(parameterType)) {
		return request.getUserPrincipal();
	}
	else if (Locale.class.equals(parameterType)) {
		return RequestContextUtils.getLocale(request);
	}
	else if (InputStream.class.isAssignableFrom(parameterType)) {
		return request.getInputStream();
	}
	else if (Reader.class.isAssignableFrom(parameterType)) {
		return request.getReader();
	}
	else if (OutputStream.class.isAssignableFrom(parameterType)) {
		this.responseArgumentUsed = true;
		return response.getOutputStream();
	}
	else if (Writer.class.isAssignableFrom(parameterType)) {
		this.responseArgumentUsed = true;
		return response.getWriter();
	}
	return super.resolveStandardArgument(parameterType, webRequest);
}
2.4、分析attrName的值
// 如果@ModelAttribute(value = "hello")注解value有值,attrName就等于value的值,所以attrName="hello"
// 如果@ModelAttribute(value = "hello")注解value没值,attrName就等于空串,所以attrName=""
String attrName = AnnotationUtils.findAnnotation(attributeMethod, ModelAttribute.class).value();
if (!"".equals(attrName) && implicitModel.containsAttribute(attrName)) {
	continue;
}
ReflectionUtils.makeAccessible(attributeMethodToInvoke);
Object attrValue = attributeMethodToInvoke.invoke(handler, args);
if ("".equals(attrName)) {
	// 获取标注了@ModelAttribute注解的方法的返回值类型
	Class<?> resolvedType = GenericTypeResolver.resolveReturnType(attributeMethodToInvoke, handler.getClass());
	// attrName就等于方法返回值类型首字母小写
	attrName = Conventions.getVariableNameForReturnType(attributeMethodToInvoke, resolvedType, attrValue);
}

总结:
@ModelAttribute(value = “hello”)
public void init(Map<String, Object> map) {}

如果value有值,那么attrName=value的值;
如果value没值,那么attrName=方法返回值类型首字母小写,比如这个方法attrName=“void”。

2.5、 @ModelAttribute注解的另一个作用
// 可以把方法运行后的返回值按照指定的key放在隐含模型中,这个指定的key就是attrName(attrName的值见2.4)
if (!implicitModel.containsAttribute(attrName)) {
	implicitModel.addAttribute(attrName, attrValue);
}
2.6、确定方法执行时要使用的每一个参数的值(详细分析)

下面的分析参照此测试代码

@RequestMapping("/updateBook")
public String updateBook(@RequestParam("author") String author, Map<String, Object> map,
                         HttpServletRequest request, @ModelAttribute("book") Book book) {
    System.out.println("更新后的 book: " + book);
    System.out.println("调用了 updateBook() 方法");
    return "success";
}
// 确定方法执行时要使用的每一个参数的值
Object[] args = resolveHandlerArguments(attributeMethodToInvoke, handler, webRequest, implicitModel);
private Object[] resolveHandlerArguments(Method handlerMethod, Object handler,
			NativeWebRequest webRequest, ExtendedModelMap implicitModel) throws Exception {

	// 获取方法参数的每一个类型
	/*
	 paramTypes
		 0 = {Class@341} "class java.lang.String"
		 1 = {Class@305} "interface java.util.Map"
		 2 = {Class@3242} "interface javax.servlet.http.HttpServletRequest"
		 3 = {Class@8233} "class cn.ilqjx.pojo.Book"
	*/
	Class<?>[] paramTypes = handlerMethod.getParameterTypes();
	// 创建了一个长度和参数个数一样多的数组,会用来保存每一个参数的值
	Object[] args = new Object[paramTypes.length];

	// 遍历方法的所有参数
	for (int i = 0; i < args.length; i++) {
		MethodParameter methodParam = new MethodParameter(handlerMethod, i);
		methodParam.initParameterNameDiscovery(this.parameterNameDiscoverer);
		GenericTypeResolver.resolveParameterType(methodParam, handler.getClass());
		String paramName = null;
		String headerName = null;
		boolean requestBodyFound = false;
		String cookieName = null;
		String pathVarName = null;
		String attrName = null;
		boolean required = false;
		String defaultValue = null;
		boolean validate = false;
		Object[] validationHints = null;
		int annotationsFound = 0;
		// 获取方法这个参数的所有注解
		Annotation[] paramAnns = methodParam.getParameterAnnotations();

		// 如果有注解就解析并保存注解的信息
		for (Annotation paramAnn : paramAnns) {
			// 第一个参数 @RequestParam("author") String author
			if (RequestParam.class.isInstance(paramAnn)) {
				RequestParam requestParam = (RequestParam) paramAnn;
				// paramName = "author"
				paramName = requestParam.value();
				// required = true(默认)
				required = requestParam.required();
				// defaultValue = null(默认)
				defaultValue = parseDefaultValueAttribute(requestParam.defaultValue());
				// 标注在这个参数上的注解的个数加1
				annotationsFound++;
			}
			else if (RequestHeader.class.isInstance(paramAnn)) {
				RequestHeader requestHeader = (RequestHeader) paramAnn;
				headerName = requestHeader.value();
				required = requestHeader.required();
				defaultValue = parseDefaultValueAttribute(requestHeader.defaultValue());
				annotationsFound++;
			}
			else if (RequestBody.class.isInstance(paramAnn)) {
				requestBodyFound = true;
				annotationsFound++;
			}
			else if (CookieValue.class.isInstance(paramAnn)) {
				CookieValue cookieValue = (CookieValue) paramAnn;
				cookieName = cookieValue.value();
				required = cookieValue.required();
				defaultValue = parseDefaultValueAttribute(cookieValue.defaultValue());
				annotationsFound++;
			}
			else if (PathVariable.class.isInstance(paramAnn)) {
				PathVariable pathVar = (PathVariable) paramAnn;
				pathVarName = pathVar.value();
				annotationsFound++;
			}
			// 第四个参数 @ModelAttribute("book") Book book
			else if (ModelAttribute.class.isInstance(paramAnn)) {
				ModelAttribute attr = (ModelAttribute) paramAnn;
				// 获取@ModelAttribute("book")注解的 value
				// attrName = "book"
				attrName = attr.value();
				// 标注在这个参数上的注解的个数加1
				annotationsFound++;
			}
			else if (Value.class.isInstance(paramAnn)) {
				defaultValue = ((Value) paramAnn).value();
			}
			else if (paramAnn.annotationType().getSimpleName().startsWith("Valid")) {
				validate = true;
				Object value = AnnotationUtils.getValue(paramAnn);
				validationHints = (value instanceof Object[] ? (Object[]) value : new Object[] {value});
			}
		}

		// 只能在参数上标一个注解,多于1个抛异常
		if (annotationsFound > 1) {
			throw new IllegalStateException("Handler parameter annotations are exclusive choices - " +
					"do not specify more than one such annotation on the same parameter: " + handlerMethod);
		}

		// 没有注解的情况
		if (annotationsFound == 0) {
			// 第三个参数 HttpServletRequest request,原生API(见2.3)
			// 解析普通参数(见2.2)
			Object argValue = resolveCommonArgument(methodParam, webRequest);
			if (argValue != WebArgumentResolver.UNRESOLVED) {
				args[i] = argValue;
			}
			else if (defaultValue != null) {
				args[i] = resolveDefaultValue(defaultValue);
			}
			else {
				// 获取参数类型
				Class<?> paramType = methodParam.getParameterType();
				// 第二个参数 Map<String, Object> map
				// 如果是 Model 类型或者是 Map类型,则将之前创建的隐含模型赋值给这个参数
				if (Model.class.isAssignableFrom(paramType) || Map.class.isAssignableFrom(paramType)) {
					if (!paramType.isAssignableFrom(implicitModel.getClass())) {
						throw new IllegalStateException("Argument [" + paramType.getSimpleName() + "] is of type " +
								"Model or Map but is not assignable from the actual model. You may need to switch " +
								"newer MVC infrastructure classes to use this argument.");
					}
					// 将隐含模型赋值给这个参数
					args[i] = implicitModel;
				}
				else if (SessionStatus.class.isAssignableFrom(paramType)) {
					args[i] = this.sessionStatus;
				}
				else if (HttpEntity.class.isAssignableFrom(paramType)) {
					args[i] = resolveHttpEntityRequest(methodParam, webRequest);
				}
				else if (Errors.class.isAssignableFrom(paramType)) {
					throw new IllegalStateException("Errors/BindingResult argument declared " +
							"without preceding model attribute. Check your handler method signature!");
				}
				else if (BeanUtils.isSimpleProperty(paramType)) {
					paramName = "";
				}
				else {
					attrName = "";
				}
			}
		}

		if (paramName != null) {
			// 确定参数的值(见2.7)
			args[i] = resolveRequestParam(paramName, required, defaultValue, methodParam, webRequest, handler);
		}
		else if (headerName != null) {
			args[i] = resolveRequestHeader(headerName, required, defaultValue, methodParam, webRequest, handler);
		}
		else if (requestBodyFound) {
			args[i] = resolveRequestBody(methodParam, webRequest, handler);
		}
		else if (cookieName != null) {
			args[i] = resolveCookieValue(cookieName, required, defaultValue, methodParam, webRequest, handler);
		}
		else if (pathVarName != null) {
			args[i] = resolvePathVariable(pathVarName, methodParam, webRequest, handler);
		}
		// 确定自定义类型参数的值(第四个参数@ModelAttribute("book") Book book)(见2.8)
		// 还要将请求中的每一个参数赋值给这个对象
		else if (attrName != null) {
			WebDataBinder binder =
					resolveModelAttribute(attrName, methodParam, implicitModel, webRequest, handler);
			boolean assignBindingResult = (args.length > i + 1 && Errors.class.isAssignableFrom(paramTypes[i + 1]));
			if (binder.getTarget() != null) {
				doBind(binder, webRequest, validate, validationHints, !assignBindingResult);
			}
			// 从数据绑定器(WebDataBinder)中获取目标对象
			args[i] = binder.getTarget();
			if (assignBindingResult) {
				args[i + 1] = binder.getBindingResult();
				i++;
			}
			implicitModel.putAll(binder.getBindingResult().getModel());
		}
	}

	return args;
}

小总结
标注解的参数:
保存注解的信息,最终得到这个注解应该对应解析的值。

没标注解的参数:
1、先判断是不是普通参数(是不是原生API),再判断是不是Model或者Map,如果是就放入隐含模型。
2、自定义类型的参数没有@ModelAttribute注解
(1)、先判断是不是原生API
(2)、再判断是不是Model或者Map
(3)、再判断是不是其他的类型,比如SessionStatus、HttpEntity、Errors
(4)、再判断是不是简单类型的属性,比如Integer,如果是paramName=""
(5)、attrName=""

2.7、确定参数的值

下面的分析参照此测试代码的第一个参数(@RequestParam(“author”) String author

@RequestMapping("/updateBook")
public String updateBook(@RequestParam("author") String author, Map<String, Object> map,
                         HttpServletRequest request, @ModelAttribute("book") Book book) {
    System.out.println("更新后的 book: " + book);
    System.out.println("调用了 updateBook() 方法");
    return "success";
}
args[i] = resolveRequestParam(paramName, required, defaultValue, methodParam, webRequest, handler);
private Object resolveRequestParam(String paramName, boolean required, String defaultValue,
			MethodParameter methodParam, NativeWebRequest webRequest, Object handlerForInitBinderCall)
			throws Exception {

	// 获取参数类型
	// paramType: class java.lang.String
	Class<?> paramType = methodParam.getParameterType();
	if (Map.class.isAssignableFrom(paramType) && paramName.length() == 0) {
		return resolveRequestParamMap((Class<? extends Map<?, ?>>) paramType, webRequest);
	}
	if (paramName.length() == 0) {
		paramName = getRequiredParameterName(methodParam);
	}
	Object paramValue = null;
	MultipartRequest multipartRequest = webRequest.getNativeRequest(MultipartRequest.class);
	if (multipartRequest != null) {
		List<MultipartFile> files = multipartRequest.getFiles(paramName);
		if (!files.isEmpty()) {
			paramValue = (files.size() == 1 ? files.get(0) : files);
		}
	}
	// 为参数赋值
	if (paramValue == null) {
		// 获取参数值
		// webRequest.getParameterValues(paramName) 多么熟悉的操作
		String[] paramValues = webRequest.getParameterValues(paramName);
		if (paramValues != null) {
			// 此时 paramValue 就有值了
			paramValue = (paramValues.length == 1 ? paramValues[0] : paramValues);
		}
	}
	if (paramValue == null) {
		if (defaultValue != null) {
			paramValue = resolveDefaultValue(defaultValue);
		}
		else if (required) {
			raiseMissingParameterException(paramName, paramType);
		}
		paramValue = checkValue(paramName, paramValue, paramType);
	}
	WebDataBinder binder = createBinder(webRequest, null, paramName);
	initBinder(handlerForInitBinderCall, paramName, binder, webRequest);
	return binder.convertIfNecessary(paramValue, paramType, methodParam);
}
2.8、确定自定义类型参数的值
WebDataBinder binder =
					resolveModelAttribute(attrName, methodParam, implicitModel, webRequest, handler);
private WebDataBinder resolveModelAttribute(String attrName, MethodParameter methodParam,
			ExtendedModelMap implicitModel, NativeWebRequest webRequest, Object handler) throws Exception {

	// Bind request parameter onto object...
	// name = attrName = "book"
	String name = attrName;
	if ("".equals(name)) {
		// 如果attrName是空串就将参数类型的首字母小写作为 key
		// 注意:和变量名没有关系,比如@ModelAttribute Book bookTest,此时的 name = "book"
		name = Conventions.getVariableNameForParameter(methodParam);
	}
	// paramType: class cn.ilqjx.pojo.Book
	Class<?> paramType = methodParam.getParameterType();
	// 目标对象
	Object bindObject;
	// 判断隐含模型中是否包含这个 key("book")
	if (implicitModel.containsKey(name)) {
		// 从隐含模型中获取,保存到目标对象
		bindObject = implicitModel.get(name);
	}
	// 如果是@SessionAttributes注解标注的属性,就从session中获取
	else if (this.methodResolver.isSessionAttribute(name, paramType)) {
		bindObject = this.sessionAttributeStore.retrieveAttribute(webRequest, name);
		if (bindObject == null) {
			raiseSessionRequiredException("Session attribute '" + name + "' required - not found in session");
		}
	}
	else {
		// 如果没标@ModelAttribute这个注解,就创建一个新的对象
		bindObject = BeanUtils.instantiateClass(paramType);
	}
	WebDataBinder binder = createBinder(webRequest, bindObject, name);
	initBinder(handler, name, binder, webRequest);
	return binder;
}

小总结
Spring MVC如何确定自定义类型的值:
1、如果隐含模型中有这个key(标了@ModelAttribute注解,就是这个注解的value属性;没标就是参数类型的首字母小写)指定的值,就将这个值赋值给bindObject。
2、如果是@SessionAttributes注解标注的属性,就从session中获取。
如果拿不到值就会抛异常,不建议使用@SessionAttributes这个注解。
3、如果都不是就利用反射创建对象

2.9、总结

确定方法参数:
如果参数有注解,就先保存注解的信息,最终得到这个注解应该对应解析的值。
1、先判断是不是原生API
2、再判断是不是Model或者Map
3、再判断是不是其他的类型,比如SessionStatus、HttpEntity、Errors
4、再判断是不是简单类型的属性,比如Integer,如果是paramName=""
5、给attrName赋值(标了@ModelAttribute(“xxx”)注解,就是指定的;没标就是"")
确定自定义类型参数的值:
(1)、如果隐含模型中有这个key(标了@ModelAttribute注解,就是这个注解的value属性;没标就是参数类型的首字母小写)指定的值,就将这个值赋值给bindObject。
2)、如果是@SessionAttributes注解标注的属性,就从session中获取。
如果拿不到值就会抛异常,不建议使用@SessionAttributes这个注解。
(3)、如果都不是就利用反射创建对象
6、拿到之前创建好的对象,使用数据绑定器(WebDataBinder)将请求中的每个数据保存到这个对象中。

九、视图解析器
1、任何方法的返回值最终都会被封装成ModelAndView对象
/*
 mv = {ModelAndView@5672} "ModelAndView: reference to view with name 'success'; model is {}"
 view = "success"
 model = {ModelMap@5682}  size = 0
 cleared = false
*/
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
2、视图渲染流程

视图渲染流程:将域中的数据在页面展示;页面就是用来渲染模型数据的。

// 来到页面的方法
processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);		
3、渲染页面
private void processDispatchResult(HttpServletRequest request, HttpServletResponse response,
			HandlerExecutionChain mappedHandler, ModelAndView mv, 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);
		}
	}

	// Did the handler return a view to render?
	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);
	}
}
4、ViewResovler与View

ViewResolver的作用就是根据视图名(方法返回值)得到视图对象。

public interface ViewResolver {

	View resolveViewName(String viewName, Locale locale) throws Exception;
}
5、如何根据方法的返回值得到View对象?
protected View resolveViewName(String viewName, Map<String, Object> model, Locale locale,
			HttpServletRequest request) throws Exception {

	// 遍历所有的 ViewResolver
	for (ViewResolver viewResolver : this.viewResolvers) {
		// ViewResolver 视图解析器根据方法的返回值得到一个 View 对象
		View view = viewResolver.resolveViewName(viewName, locale);
		if (view != null) {
			return view;
		}
	}
	return null;
}

6、创建View对象
public View resolveViewName(String viewName, Locale locale) throws Exception {
	if (!isCache()) {
		return createView(viewName, locale);
	}
	else {
		Object cacheKey = getCacheKey(viewName, locale);
		View view = this.viewAccessCache.get(cacheKey);
		if (view == null) {
			synchronized (this.viewCreationCache) {
				view = this.viewCreationCache.get(cacheKey);
				if (view == null) {
					// Ask the subclass to create the View object.
					// 根据方法的返回值 viewName(视图名)创建 View 对象
					view = createView(viewName, locale);
					if (view == null && this.cacheUnresolved) {
						view = UNRESOLVED_VIEW;
					}
					if (view != null) {
						// 放缓存里了,下一次使用就不需要创建了
						this.viewAccessCache.put(cacheKey, view);
						this.viewCreationCache.put(cacheKey, view);
						if (logger.isTraceEnabled()) {
							logger.trace("Cached view [" + cacheKey + "]");
						}
					}
				}
			}
		}
		return (view != UNRESOLVED_VIEW ? view : null);
	}
}
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;
	}
	// Check for special "redirect:" prefix.
	// 判断是否是 redirect 前缀
	if (viewName.startsWith(REDIRECT_URL_PREFIX)) {
		String redirectUrl = viewName.substring(REDIRECT_URL_PREFIX.length());
		// 创建 RedirectView 对象
		RedirectView view = new RedirectView(redirectUrl, isRedirectContextRelative(), isRedirectHttp10Compatible());
		return applyLifecycleMethods(viewName, view);
	}
	// Check for special "forward:" prefix.
	// 判断是否是 forward 前缀
	if (viewName.startsWith(FORWARD_URL_PREFIX)) {
		String forwardUrl = viewName.substring(FORWARD_URL_PREFIX.length());
		// 创建 InternalResourceView 对象
		return new InternalResourceView(forwardUrl);
	}
	// Else fall back to superclass implementation: calling loadView.
	// 没有前缀就使用父类默认创建一个View
	return super.createView(viewName, locale);
}

拼串得到页面地址

7、返回View对象

1、视图解析器得到View对象的流程就是,所有配置的视图解析器都来尝试根据视图名得到View对象;如果能得到就返回,得不到就下一个。
2、调用View对象的render()方法

public void render(Map<String, ?> model, HttpServletRequest request, HttpServletResponse response) throws Exception {
	if (logger.isTraceEnabled()) {
		logger.trace("Rendering view with name '" + this.beanName + "' with model " + model +
			" and static attributes " + this.staticAttributes);
	}

	Map<String, Object> mergedModel = createMergedOutputModel(model, request, response);

	prepareResponse(request, response);
	// 渲染要给页面输出的所有数据
	renderMergedOutputModel(mergedModel, request, response);
}
8、为什么请求域中能够获得隐含模型中的数据?
// 把隐含模型中的数据放在请求域中
protected void exposeModelAsRequestAttributes(Map<String, Object> model, HttpServletRequest request) throws Exception {
	for (Map.Entry<String, Object> entry : model.entrySet()) {
		String modelName = entry.getKey();
		Object modelValue = entry.getValue();
		if (modelValue != null) {
			// 答案
			request.setAttribute(modelName, modelValue);
			if (logger.isDebugEnabled()) {
				logger.debug("Added model object '" + modelName + "' of type [" + modelValue.getClass().getName() +
						"] to request in view with name '" + getBeanName() + "'");
			}
		}
		else {
			request.removeAttribute(modelName);
			if (logger.isDebugEnabled()) {
				logger.debug("Removed model object '" + modelName +
						"' from request in view with name '" + getBeanName() + "'");
			}
		}
	}
}
9、总结

视图解析器只是为了得到视图对象,视图对象才能真正的转发(将隐含模型中的数据放在请求域中)或者重定向到页面,视图对象才能真正的渲染视图。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值