spring5.1.x源码解析之九(spring-mvc)

文章目录

  • 配置文件
    • web.xml
    • web-servlet.xml
    • application.xml
    • Controller
    • PO
    • jsp
    • 加载顺序
  • ContextLoaderListener
  • DispatcherServlet
    • 加载过程
    • 加载
    • 执行请求
    • 获取处理映射器
    • 没找到处理
    • 获取适配器
    • last-modified头处理
    • 拦截器的调用
    • 返回视图
    • 异常处理
    • 页面处理
    • 页面跳转

配置文件

web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xmlns="http://java.sun.com/xml/ns/javaee"
         xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
         id="WebApp_ID" version="2.5">

    <display-name>springmvc</display-name>

    <!-- ContextLoaderListener读取
    声明应用范围(整个WEB项目)内的上下文初始化参数。-->
    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>classpath:application.xml</param-value>
    </context-param>

    <!-- 注册spring-mvc核心控制器
     默认/WEB-INF/DispatcherServlet-servlet(控制器名字-servlet).xml下寻找配置的spring文件
        contextConfigLocation:通知DispatcherServlet去指定的目录加载spring-mvc.xml -->
    <servlet>
        <servlet-name>web-servlet</servlet-name>
        <servlet-class>
            org.springframework.web.servlet.DispatcherServlet
        </servlet-class>
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>classpath:web-servlet.xml</param-value>
        </init-param>
        <!-- 4.服务器启动后立即加载SpringMVC配置文件 -->
        <load-on-startup>1</load-on-startup>
    </servlet>

    <!--
            *.html:过滤所有html
            /:所有访问的地址都由dispatchServlet进行解析,对于静态配置文件(js,txt)需要配置不让dispatchServlet进行解析,
                    使用此种方式可以实现RESTful风格的url
            /*:最终要转发到一个jsp页面时,任然会有dispatchServlet解析jsp地址,不能根据jsp找到handler,报错
             -->
    
        web-servlet
        *.html
    

    
    
        org.springframework.web.context.ContextLoaderListener
    


web-servlet.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:p="http://www.springframework.org/schema/p"
       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/mvc
        http://www.springframework.org/schema/mvc/spring-mvc.xsd
        http://www.springframework.org/schema/context
         http://www.springframework.org/schema/context/spring-context.xsd">

    <bean id="simpleUrlMapping" class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
        <property name="mappings">
            <props>
                <prop key="/userlist.html">userController</prop>
            </props>
        </property>
    </bean>
    <bean id="userController" name="/userlist.html" class="org.example.mvc.UserController"></bean>
</beans>

application.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"
       xsi:schemaLocation="
        http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd ">
    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/"></property>
        <property name="suffix" value=".jsp"></property>
    </bean>
</beans>

Controller

package org.example.mvc;

import org.example.jdbc.User;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.AbstractController;
import org.springframework.web.servlet.mvc.LastModified;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;


public class UserController extends AbstractController implements LastModified {

    @Override
    protected ModelAndView handleRequestInternal(HttpServletRequest request, HttpServletResponse response) throws Exception {
        String test = (String) getServletContext().getAttribute("test");
        System.out.println(test);
        List<User> userList = new ArrayList<>();
        userList.add(new User(1L, "name1", "1"));
        userList.add(new User(2L, "name2", "2"));
        return new ModelAndView("userlist", "users", userList);
    }

    private long lastModified;

    @Override
    public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception {
        //点击后再次请求页面
        /*response.getWriter().write("");
        return null;*/

        String test = (String) getServletContext().getAttribute("test");
        System.out.println(test);
        List<User> userList = new ArrayList<>();
        userList.add(new User(1L, "name1", "1"));
        userList.add(new User(2L, "name2", "2"));
        return new ModelAndView("userlist", "users", userList);
    }

    @Override
    public long getLastModified(HttpServletRequest httpServletRequest) {
        if (lastModified == 0L) {
            //第一次或处理逻辑更新时,重新返回上次修改值
            lastModified = System.currentTimeMillis();
        }
        //return lastModified;
        return -1;
    }
}


PO

package org.example.jdbc;


import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;


@Data
@AllArgsConstructor
public class User {
    private Long id;
    private String name;
    private String passwd;
}

jsp

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<html>
<body>
<h2>Hello World!</h2>
<c:forEach items="${users}" var="user">
    <c:out value="${user.name}"/>
    <c:out value="${user.passwd}"/>
</c:forEach>

</body>
</html>

加载顺序

监听器加载application.xml配置文件,生成bean
在这里插入图片描述
spring5.1.x源码解析之九(spring-mvc)_第1张图片
接着注入拦截器,加载web-servlet.xml,这个配置文件主要配置一些跟web相关的对象,当然也可以放在application.xml里面加载
spring5.1.x源码解析之九(spring-mvc)_第2张图片
spring这里用的是servlet拦截,拦截的我这里设置的是*.html结尾的地址
spring5.1.x源码解析之九(spring-mvc)_第3张图片
拦截了之后,会查找访问的地址,主要在这儿配置
spring5.1.x源码解析之九(spring-mvc)_第4张图片
访问这个Controller后,返回页面,视图是userList
spring5.1.x源码解析之九(spring-mvc)_第5张图片
接着交给配置文件用来做一些收尾的工作,比如添加前后缀
spring5.1.x源码解析之九(spring-mvc)_第6张图片
接着就访问userList.jsp了,这里主要做的是伪静态处理.因为后缀是html,所以用户访问的时候就不知道是具体用那种语言解析的了,其实在访问的时候还有2种技术能够起到混淆的左右,第一种是urlwrite,第二种是短网址.有空我写出来.
spring5.1.x源码解析之九(spring-mvc)_第7张图片
spring5.1.x源码解析之九(spring-mvc)_第8张图片

ContextLoaderListener

首先查看监听器ContextLoaderListener,监听器继承了ServletContextListener,可以在这个监听器中存放一些tomcat启动时就要完成的代码,主要提供2个方法,分别开启和关闭的时候执行.

	@Override
	// 生之后调用
	public void contextInitialized(ServletContextEvent event) {
	//初始化WebAPPlicationContext,也就是spring容器,对web的支持
		initWebApplicationContext(event.getServletContext());
	}


	/**
	 * Close the root web application context.
	 */
	@Override
	// 死之前调用
	public void contextDestroyed(ServletContextEvent event) {
		closeWebApplicationContext(event.getServletContext());
		ContextCleanupListener.cleanupAttributes(event.getServletContext());
	}
/*
	重复创建上下文检测
	创建上下文
	设置父上下文,如果非活动且没刷新下
		配置刷新上下文
	存储域值对象中
	设置2个副本
	 */
	public WebApplicationContext initWebApplicationContext(ServletContext servletContext) {
		//重复创建上下文,异常
		if (servletContext.getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE) != null) {
			throw new IllegalStateException(
					"Cannot initialize context because there is already a root application context present - " +
					"check whether you have multiple ContextLoader* definitions in your web.xml!");
		}

		servletContext.log("Initializing Spring root WebApplicationContext");
		Log logger = LogFactory.getLog(ContextLoader.class);
		if (logger.isInfoEnabled()) {
			logger.info("Root WebApplicationContext: initialization started");
		}
		long startTime = System.currentTimeMillis();

		try {
			// Store context in local instance variable, to guarantee that
			// it is available on ServletContext shutdown.
			//在ServletContext关闭时依旧可用,因为本类存了副本
			if (this.context == null) {
				//初始化WebApplicationContext
				this.context = createWebApplicationContext(servletContext);
			}
			if (this.context instanceof ConfigurableWebApplicationContext) {
				ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext) this.context;
				//是否活动状态
				if (!cwac.isActive()) {
					// The context has not yet been refreshed -> provide services such as
					// setting the parent context, setting the application context id, etc
					//不是活动状态,也没有刷新,设置父上下文
					if (cwac.getParent() == null) {
						// The context instance was injected without an explicit parent ->
						// determine parent for root web application context, if any.
						ApplicationContext parent = loadParentContext(servletContext);
						cwac.setParent(parent);
					}
					//配置刷新上下文
					configureAndRefreshWebApplicationContext(cwac, servletContext);
				}
			}
			//存储域值对象中,代表整个web应用对象,贯穿整个tomcat生命周期
			servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, this.context);

			ClassLoader ccl = Thread.currentThread().getContextClassLoader();
			//确定同一类加载器,则赋值
			if (ccl == ContextLoader.class.getClassLoader()) {
				currentContext = this.context;
			}
			else if (ccl != null) {
				//存储类加载器=>上下文
				currentContextPerThread.put(ccl, this.context);
			}

			if (logger.isInfoEnabled()) {
				long elapsedTime = System.currentTimeMillis() - startTime;
				logger.info("Root WebApplicationContext initialized in " + elapsedTime + " ms");
			}

			return this.context;
		}
		catch (RuntimeException | Error ex) {
			logger.error("Context initialization failed", ex);
			servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, ex);
			throw ex;
		}
	}
	protected WebApplicationContext createWebApplicationContext(ServletContext sc) {
		Class<?> contextClass = determineContextClass(sc);
		if (!ConfigurableWebApplicationContext.class.isAssignableFrom(contextClass)) {
			throw new ApplicationContextException("Custom context class [" + contextClass.getName() +
					"] is not of type [" + ConfigurableWebApplicationContext.class.getName() + "]");
		}
		return (ConfigurableWebApplicationContext) BeanUtils.instantiateClass(contextClass);
	}
/*
	域值对象获取application上下文类名
	如果没有的话,从配置文件获取
	 */
	protected Class<?> determineContextClass(ServletContext servletContext) {
		String contextClassName = servletContext.getInitParameter(CONTEXT_CLASS_PARAM);
		if (contextClassName != null) {
			try {
				return ClassUtils.forName(contextClassName, ClassUtils.getDefaultClassLoader());
			}
			catch (ClassNotFoundException ex) {
				throw new ApplicationContextException(
						"Failed to load custom context class [" + contextClassName + "]", ex);
			}
		}
		else {
			//配置文件获取类全限命名
			contextClassName = defaultStrategies.getProperty(WebApplicationContext.class.getName());
			try {
				return ClassUtils.forName(contextClassName, ContextLoader.class.getClassLoader());
			}
			catch (ClassNotFoundException ex) {
				throw new ApplicationContextException(
						"Failed to load default context class [" + contextClassName + "]", ex);
			}
		}
	}
private static final Properties defaultStrategies;

	static {
		// Load default strategy implementations from properties file.
		// This is currently strictly internal and not meant to be customized
		// by application developers.
		try {
			//加载ContextLoader.properties获取spring容器的全限命名
			//因为没有设置路径,所以就在当前路径
			//可看源码下没有,jar包当前类目录下有,原因是因为打jar的时候,默认把resources目录下的文件和main目录合并了
			ClassPathResource resource = new ClassPathResource(DEFAULT_STRATEGIES_PATH, ContextLoader.class);
			//加载
			defaultStrategies = PropertiesLoaderUtils.loadProperties(resource);
		}
		catch (IOException ex) {
			throw new IllegalStateException("Could not load 'ContextLoader.properties': " + ex.getMessage());
		}
	}

可以发现2者路径一致
spring5.1.x源码解析之九(spring-mvc)_第9张图片
spring5.1.x源码解析之九(spring-mvc)_第10张图片

org.springframework.web.context.WebApplicationContext=org.springframework.web.context.support.XmlWebApplicationContext

	/*
		上下文构造id
		设置上下文属性,如阈值对象,加载文件路径
		替换占位符
		对上下文进行一些扩展操作
		刷新上下文
	 */
	protected void configureAndRefreshWebApplicationContext(ConfigurableWebApplicationContext wac, ServletContext sc) {
		if (ObjectUtils.identityToString(wac).equals(wac.getId())) {
			// The application context id is still set to its original default value
			// -> assign a more useful id based on available information
			String idParam = sc.getInitParameter(CONTEXT_ID_PARAM);
			if (idParam != null) {
				wac.setId(idParam);
			}
			else {
				// Generate default id...
				//构造默认id
				//value=org.springframework.web.context.WebApplicationContext:/tomcat设置的项目名
				wac.setId(ConfigurableWebApplicationContext.APPLICATION_CONTEXT_ID_PREFIX +
						ObjectUtils.getDisplayString(sc.getContextPath()));
			}
		}

		//域值对象设置spring容器中
		wac.setServletContext(sc);
		//获取xml配置的路径,classpath:springmvc.xml
		String configLocationParam = sc.getInitParameter(CONFIG_LOCATION_PARAM);
		if (configLocationParam != null) {
			wac.setConfigLocation(configLocationParam);
		}

		// The wac environment's #initPropertySources will be called in any case when the context
		// is refreshed; do it eagerly here to ensure servlet property sources are in place for
		// use in any post-processing or initialization that occurs below prior to #refresh
		ConfigurableEnvironment env = wac.getEnvironment();
		if (env instanceof ConfigurableWebEnvironment) {
			//替换占位符
			((ConfigurableWebEnvironment) env).initPropertySources(sc, null);
		}

		//对上下文进行一些扩展操作,在刷新之前
		customizeContext(sc, wac);

		//刷新上下文
		wac.refresh();
	}

DispatcherServlet

加载过程

servlet生命周期由容器控制
初始化
servlet容器加载servlet.class,读到内存中
容器创建servletConfig,里面包含servlet的初始化配置信息
容器创建servlet对象,并调用init()初始化
运行
容器接收请求时,分别创建request和response对象,并传递给service()
service()通过servletRequest获得请求,处理,并通过servletResponse对象生成响应结果
最终销毁servletRequest和servletResponse,不管请求是get/post,最终都由service()处理
销毁
web应用终止,首先调用servlet销毁方法,销毁servletConfig

加载

/*
	解析配置文件init-param
	将servlet封装BeanWrapper,从而能spring管理
	设置自定义属性编辑器
	子类覆盖
	属性注入
	子类覆盖
	 */
	public final void init() throws ServletException {

		// Set bean properties from init parameters.
		//解析init-param并封装,PropertyValues支持的所有属性都可以web.xml配置
		PropertyValues pvs = new ServletConfigPropertyValues(getServletConfig(), this.requiredProperties);
		if (!pvs.isEmpty()) {
			try {
				//将servlet封装BeanWrapper,从而能spring管理
				BeanWrapper bw = PropertyAccessorFactory.forBeanPropertyAccess(this);
				ResourceLoader resourceLoader = new ServletContextResourceLoader(getServletContext());
				//注册自定义属性编辑器,遇到Resource使用ResourceEditor解析
				bw.registerCustomEditor(Resource.class, new ResourceEditor(resourceLoader, getEnvironment()));
				//留给子类覆盖
				initBeanWrapper(bw);
				//属性注入
				bw.setPropertyValues(pvs, true);
			}
			catch (BeansException ex) {
				if (logger.isErrorEnabled()) {
					logger.error("Failed to set bean properties on servlet '" + getServletName() + "'", ex);
				}
				throw ex;
			}
		}

		// Let subclasses do whatever initialization they like.
		//子类覆盖
		initServletBean();
	}
	/*
		对init-param封装以及验证
		 */
		public ServletConfigPropertyValues(ServletConfig config, Set<String> requiredProperties)
				throws ServletException {

			//验证那些必须属性
			Set<String> missingProps = (!CollectionUtils.isEmpty(requiredProperties) ?
					new HashSet<>(requiredProperties) : null);

			//获取init-param
			Enumeration<String> paramNames = config.getInitParameterNames();
			while (paramNames.hasMoreElements()) {
				String property = paramNames.nextElement();
				Object value = config.getInitParameter(property);
				addPropertyValue(new PropertyValue(property, value));
				if (missingProps != null) {
					missingProps.remove(property);
				}
			}

			// Fail if we are still missing properties.
			//missingProps依旧还有必须存在的值,异常
			if (!CollectionUtils.isEmpty(missingProps)) {
				throw new ServletException(
						"Initialization from ServletConfig for servlet '" + config.getServletName() +
						"' failed; the following required properties were missing: " +
						StringUtils.collectionToDelimitedString(missingProps, ", "));
			}
		}
	/*
	初始化容器
	留给子类扩展
	日志打印加载时间
	 */
	@Override
	protected final void initServletBean() throws ServletException {
		getServletContext().log("Initializing Spring " + getClass().getSimpleName() + " '" + getServletName() + "'");
		if (logger.isInfoEnabled()) {
			logger.info("Initializing Servlet '" + getServletName() + "'");
		}
		long startTime = System.currentTimeMillis();

		try {
			//初始化web容器
			this.webApplicationContext = initWebApplicationContext();
			//子类覆盖
			initFrameworkServlet();
		}
		catch (ServletException | RuntimeException ex) {
			logger.error("Context initialization failed", ex);
			throw ex;
		}

		if (logger.isDebugEnabled()) {
			String value = this.enableLoggingRequestDetails ?
					"shown which may lead to unsafe logging of potentially sensitive data" :
					"masked to prevent unsafe logging of potentially sensitive data";
			logger.debug("enableLoggingRequestDetails='" + this.enableLoggingRequestDetails +
					"': request parameters and headers will be " + value);
		}

		if (logger.isInfoEnabled()) {
			logger.info("Completed initialization in " + (System.currentTimeMillis() - startTime) + " ms");
		}
	}
/*	对webApplicationContext进行设置和刷新,如果构造时注入的话
			从域值对象获取spring容器,如果没有的话
	创建新容器,如果没有
			刷新
	添加容器到域值对象*/
	protected WebApplicationContext initWebApplicationContext() {
		//spring非常喜欢封装一个工具类,来用来对某个对象的获取
		//在个方法里面看到了主要对异常的处理.get到了
		WebApplicationContext rootContext =
				WebApplicationContextUtils.getWebApplicationContext(getServletContext());
		WebApplicationContext wac = null;

		//此类继承了ApplicationContextAware,所以会构造注入webApplicationContext
		if (this.webApplicationContext != null) {
			// A context instance was injected at construction time -> use it
			wac = this.webApplicationContext;
			if (wac instanceof ConfigurableWebApplicationContext) {
				ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext) wac;
				if (!cwac.isActive()) {
					// The context has not yet been refreshed -> provide services such as
					// setting the parent context, setting the application context id, etc
					if (cwac.getParent() == null) {
						// The context instance was injected without an explicit parent -> set
						// the root application context (if any; may be null) as the parent
						//非活动且无父,则加载父
						cwac.setParent(rootContext);
					}
					//配置和刷新
					configureAndRefreshWebApplicationContext(cwac);
				}
			}
		}
		if (wac == null) {
			// No context instance was injected at construction time -> see if one
			// has been registered in the servlet context. If one exists, it is assumed
			// that the parent context (if any) has already been set and that the
			// user has performed any initialization such as setting the context id
			//根据contextAttribute获取spring容器,web.xml配置
			//域值对象获取spring容器
			wac = findWebApplicationContext();
		}
		if (wac == null) {
			// No context instance is defined for this servlet -> create a local one
			//创建新的容器,并以rootContext当parent
			//在这里执行了onRefresh(wac),主要是通过监听器执行的
			wac = createWebApplicationContext(rootContext);
		}

		if (!this.refreshEventReceived) {
			// Either the context is not a ConfigurableApplicationContext with refresh
			// support or the context injected at construction time had already been
			// refreshed -> trigger initial onRefresh manually here.
			synchronized (this.onRefreshMonitor) {
				//刷新,主要注册各种解析器,比如视图,url映射子类的
				onRefresh(wac);
			}
		}

		if (this.publishContext) {
			// Publish the context as a servlet context attribute.
			//添加容器到域值对象
			String attrName = getServletContextAttributeName();
			getServletContext().setAttribute(attrName, wac);
		}

		return wac;
}
	protected WebApplicationContext createWebApplicationContext(@Nullable WebApplicationContext parent) {
		return createWebApplicationContext((ApplicationContext) parent);
	}
	/*
	获取contextClass,以此为创建spring容器依据
	配置环境变量,parent,location(xml配置)
	配置和刷新
	 */
	protected WebApplicationContext createWebApplicationContext(@Nullable ApplicationContext parent) {
		//获取servlet初始化参数contextClass,默认XmlWebApplicationContext
		Class<?> contextClass = getContextClass();
		if (!ConfigurableWebApplicationContext.class.isAssignableFrom(contextClass)) {
			throw new ApplicationContextException(
					"Fatal initialization error in servlet with name '" + getServletName() +
					"': custom WebApplicationContext class [" + contextClass.getName() +
					"] is not of type ConfigurableWebApplicationContext");
		}
		ConfigurableWebApplicationContext wac =
				(ConfigurableWebApplicationContext) BeanUtils.instantiateClass(contextClass);

		//设置环境变量
		wac.setEnvironment(getEnvironment());
		//设置listen初始化的parent
		wac.setParent(parent);
		String configLocation = getContextConfigLocation();
		if (configLocation != null) {
			//配置location,xml配置
			wac.setConfigLocation(configLocation);
		}
		//配置和刷新
		configureAndRefreshWebApplicationContext(wac);

		return wac;
	}
	/*
	spring容器设置属性
	扩展
	刷新
	 */
	protected void configureAndRefreshWebApplicationContext(ConfigurableWebApplicationContext wac) {
		//设置容器全局唯一标识
		if (ObjectUtils.identityToString(wac).equals(wac.getId())) {
			// The application context id is still set to its original default value
			// -> assign a more useful id based on available information
			if (this.contextId != null) {
				wac.setId(this.contextId);
			}
			else {
				// Generate default id...

				wac.setId(ConfigurableWebApplicationContext.APPLICATION_CONTEXT_ID_PREFIX +
						ObjectUtils.getDisplayString(getServletContext().getContextPath()) + '/' + getServletName());
			}
		}

		//设置域值对象
		wac.setServletContext(getServletContext());
		//设置ServletConfig
		wac.setServletConfig(getServletConfig());
		//设置命名空间
		wac.setNamespace(getNamespace());
		//设置监听器
		wac.addApplicationListener(new SourceFilteringListener(wac, new ContextRefreshListener()));

		// The wac environment's #initPropertySources will be called in any case when the context
		// is refreshed; do it eagerly here to ensure servlet property sources are in place for
		// use in any post-processing or initialization that occurs below prior to #refresh
		//环境变量替换
		ConfigurableEnvironment env = wac.getEnvironment();
		if (env instanceof ConfigurableWebEnvironment) {
			((ConfigurableWebEnvironment) env).initPropertySources(getServletContext(), getServletConfig());
		}

		//子类覆盖
		postProcessWebApplicationContext(wac);
		//对上下文进行一些扩展操作,在刷新之前
		applyInitializers(wac);
		//刷新
		wac.refresh();
	}

	@Override
	protected void onRefresh(ApplicationContext context) {
		initStrategies(context);
	}

	protected void initStrategies(ApplicationContext context) {
		//处理文件上传,如果想使用multipart,则需要添加对应解析器
		initMultipartResolver(context);
		//国际化,分别支持url,session,cookie三种配置
		initLocaleResolver(context);
		//theme主题控制页面风格,
		initThemeResolver(context);
		//处理映射器:Controller映射处理,可设置多个,分别根据优先级处理
		initHandlerMappings(context);
		//适配器,通过处理映射器得到处理,轮询适配器,查找能够处理当前HTTP请求的,从而适配当前HTTP请求
		initHandlerAdapters(context);
		//异常处理器,返回一个ModelAndView
		initHandlerExceptionResolvers(context);
		//当Controller没有返回视图,response没有流,则通过实现了此接口的类来确定此种情况下返回viewName的约定
					//支持前后缀等
		initRequestToViewNameTranslator(context);
		//选择view渲染
		initViewResolvers(context);
		//请求存储
			//场景,重定向的时候,定向后依旧能使用定向前数据
		initFlashMapManager(context);
	}

private void initHandlerMappings(ApplicationContext context) {
		this.handlerMappings = null;
		//可在web.xml设置detectAllHandlerMappings=false,
		//会查找默认名handlerMapping处理
		//如果没找到,则加载默认配置文件
		//DispatcherService.properties加载(没自定义Strategies的情况下)
		if (this.detectAllHandlerMappings) {
			// Find all HandlerMappings in the ApplicationContext, including ancestor contexts.
			Map<String, HandlerMapping> matchingBeans =
					BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerMapping.class, true, false);
			if (!matchingBeans.isEmpty()) {
				this.handlerMappings = new ArrayList<>(matchingBeans.values());
				// We keep HandlerMappings in sorted order.
				AnnotationAwareOrderComparator.sort(this.handlerMappings);
			}
		}
		else {
			try {
				HandlerMapping hm = context.getBean(HANDLER_MAPPING_BEAN_NAME, HandlerMapping.class);
				this.handlerMappings = Collections.singletonList(hm);
			}
			catch (NoSuchBeanDefinitionException ex) {
				// Ignore, we'll add a default HandlerMapping later.
			}
		}

		// Ensure we have at least one HandlerMapping, by registering
		// a default HandlerMapping if no other mappings are found.
		if (this.handlerMappings == null) {
			this.handlerMappings = getDefaultStrategies(context, HandlerMapping.class);
			if (logger.isTraceEnabled()) {
				logger.trace("No HandlerMappings declared for servlet '" + getServletName() +
						"': using default strategies from DispatcherServlet.properties");
			}
		}
	}

执行请求

get/post以及其他请求都走processRequest方法,统一处理

	@Override
	protected final void doGet(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {

		processRequest(request, response);
	}

	/**
	 * Delegate POST requests to {@link #processRequest}.
	 *
	 * @see #doService
	 */
	@Override
	protected final void doPost(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {

		processRequest(request, response);
	}
/*
	获取当前线程localeContext,requestAttributes
	注册回调拦截器
	绑定当前线程localeContext,requestAttributes
	执行
	恢复当前线程localeContext,requestAttributes
	发布监听器
	 */
	protected final void processRequest(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {

		long startTime = System.currentTimeMillis();
		Throwable failureCause = null;

		//获取当前线程localeContext
		LocaleContext previousLocaleContext = LocaleContextHolder.getLocaleContext();
		LocaleContext localeContext = buildLocaleContext(request);

		//获取当前线程requestAttributes
		RequestAttributes previousAttributes = RequestContextHolder.getRequestAttributes();
		ServletRequestAttributes requestAttributes = buildRequestAttributes(request, response, previousAttributes);

		//注册回调拦截器
		WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
		asyncManager.registerCallableInterceptor(FrameworkServlet.class.getName(), new RequestBindingInterceptor());

		//绑定当前线程
		initContextHolders(request, localeContext, requestAttributes);

		try {
			//执行
			doService(request, response);
		} catch (ServletException | IOException ex) {
			failureCause = ex;
			throw ex;
		} catch (Throwable ex) {
			failureCause = ex;
			throw new NestedServletException("Request processing failed", ex);
		} finally {
			//重置
			resetContextHolders(request, previousLocaleContext, previousAttributes);
			if (requestAttributes != null) {
				requestAttributes.requestCompleted();
			}
			logResult(request, response, failureCause, asyncManager);
			//发布监听器
			publishRequestHandledEvent(request, response, startTime, failureCause);
		}
	}
	/*
	设置相关属性到request
	设置请求缓存
	执行
	 */
	protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {
		logRequest(request);

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

		// Make framework objects available to handlers and view objects.
		//设置相关属性,THEME,CONTEXT
		request.setAttribute(WEB_APPLICATION_CONTEXT_ATTRIBUTE, getWebApplicationContext());
		request.setAttribute(LOCALE_RESOLVER_ATTRIBUTE, this.localeResolver);
		request.setAttribute(THEME_RESOLVER_ATTRIBUTE, this.themeResolver);
		request.setAttribute(THEME_SOURCE_ATTRIBUTE, getThemeSource());

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

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

	/*
	Multipart类型处理
	获取处理映射器,内部封装Controller
	获取适配器
	执行last-modified头,如果适配器支持
	请求前调用拦截器
	适配器调用Controller,返回视图
	设置视图默认名称
	请求后调用拦截器
	视图跳转,以及拦截器请求完执行
	清除MultipartHttpServletRequest
	 */
	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 {
				//如果是Multipart类型的request,转成MultipartHttpServletRequest
				processedRequest = checkMultipart(request);
				multipartRequestParsed = (processedRequest != request);

				// Determine handler for the current request.
				//获取handlerMappings
				//获取处理映射器,内部封装Controller
				mappedHandler = getHandler(processedRequest);
				if (mappedHandler == null) {
					//没找到,response直接返回
					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.
				//执行last-modified头,如果适配器支持
				String method = request.getMethod();
				boolean isGet = "GET".equals(method);
				if (isGet || "HEAD".equals(method)) {
					//增加对lastModified的支持,需要controller继承LastModified
					long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
					if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
						return;
					}
				}

				//请求前调用拦截器
				if (!mappedHandler.applyPreHandle(processedRequest, response)) {
					return;
				}

				// Actually invoke the handler.
				//适配器调用Controller,返回视图
				mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

				if (asyncManager.isConcurrentHandlingStarted()) {
					return;
				}
				//设置视图默认名称,如果没设置视图名称的话
				applyDefaultViewName(processedRequest, mv);
				//请求后调用拦截器
				mappedHandler.applyPostHandle(processedRequest, response, mv);
			}
			catch (Exception ex) {
				dispatchException = ex;
			}
			catch (Throwable err) {
				// As of 4.3, we're processing Errors thrown from handler methods as well,
				// making them available for @ExceptionHandler methods and other scenarios.
				dispatchException = new NestedServletException("Handler dispatch failed", err);
			}
			//视图跳转,以及拦截器请求完执行
			processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
		}
		catch (Exception ex) {
			triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
		}
		catch (Throwable err) {
			triggerAfterCompletion(processedRequest, response, mappedHandler,
					new NestedServletException("Handler processing failed", err));
		}
		finally {
			if (asyncManager.isConcurrentHandlingStarted()) {
				// Instead of postHandle and afterCompletion
				if (mappedHandler != null) {
					mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
				}
			}
			else {
				// Clean up any resources used by a multipart request.
				//清除MultipartHttpServletRequest
				if (multipartRequestParsed) {
					cleanupMultipart(processedRequest);
				}
			}
		}
	}

获取处理映射器

	@Nullable
	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;
	}
/*
	获取Controller
	加入拦截器到执行链,以便更好对controller处理
	 */
	public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
				//获取request对应的Controller,封装成HandlerExecutionChain
		Object handler = getHandlerInternal(request);
		if (handler == null) {
			//使用默认handler
			handler = getDefaultHandler();
		}
		//如果依旧没有,返回null
		if (handler == null) {
			return null;
		}
		// Bean name or resolved handler?
		//如果是handler名字,则容器获取
		if (handler instanceof String) {
			String handlerName = (String) handler;
			handler = obtainApplicationContext().getBean(handlerName);
		}

		//加入拦截器到执行链,以便更好对controller处理
		HandlerExecutionChain executionChain = getHandlerExecutionChain(handler, request);

		if (logger.isTraceEnabled()) {
			logger.trace("Mapped to " + handler);
		}
		else if (logger.isDebugEnabled() && !request.getDispatcherType().equals(DispatcherType.ASYNC)) {
			logger.debug("Mapped to " + executionChain.getHandler());
		}

		if (CorsUtils.isCorsRequest(request)) {
			CorsConfiguration globalConfig = this.corsConfigurationSource.getCorsConfiguration(request);
			CorsConfiguration handlerConfig = getCorsConfiguration(handler, request);
			CorsConfiguration config = (globalConfig != null ? globalConfig.combine(handlerConfig) : handlerConfig);
			executionChain = getCorsHandlerExecutionChain(request, executionChain, config);
		}

		return executionChain;
	}
/*
	handler根据路径处理获取Contorller
	 */
	protected Object getHandlerInternal(HttpServletRequest request) throws Exception {
		//截取用于匹配的url有效路径
		String lookupPath = getUrlPathHelper().getLookupPathForRequest(request);
		//根据路径寻找handler
		Object handler = lookupHandler(lookupPath, request);
		if (handler == null) {
			// We need to care for the default handler directly, since we need to
			// expose the PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE for it as well.
			Object rawHandler = null;
			//如果路径是/,使用rootHandler处理
			if ("/".equals(lookupPath)) {
				rawHandler = getRootHandler();
			}
			//使用默认handler
			if (rawHandler == null) {
				rawHandler = getDefaultHandler();
			}
			if (rawHandler != null) {
				// Bean name or resolved handler?
				//根据beanName获取对应bean
				if (rawHandler instanceof String) {
					String handlerName = (String) rawHandler;
					rawHandler = obtainApplicationContext().getBean(handlerName);
				}
				//模板方法
				validateHandler(rawHandler, request);
				handler = buildPathExposingHandler(rawHandler, lookupPath, lookupPath, null);
			}
		}
		return handler;
	}
/*
	通过路径匹配或通配符匹配返回Contorller
	 */
	protected Object lookupHandler(String urlPath, HttpServletRequest request) throws Exception {
		// Direct match?
		//直接匹配路径获取Controller
		/*
		   
        
            
                userController
            
        
    
		 */
		Object handler = this.handlerMap.get(urlPath);
		if (handler != null) {
			// Bean name or resolved handler?
			if (handler instanceof String) {
				String handlerName = (String) handler;
				handler = obtainApplicationContext().getBean(handlerName);
			}
			//子类实现
			validateHandler(handler, request);
			//构造HandlerExecutionChain,封装controller
			return buildPathExposingHandler(handler, urlPath, urlPath, null);
		}

		// Pattern match?
		//通配符匹配handler
		List<String> matchingPatterns = new ArrayList<>();
		for (String registeredPattern : this.handlerMap.keySet()) {
			if (getPathMatcher().match(registeredPattern, urlPath)) {
				matchingPatterns.add(registeredPattern);
			}
			else if (useTrailingSlashMatch()) {
				if (!registeredPattern.endsWith("/") && getPathMatcher().match(registeredPattern + "/", urlPath)) {
					matchingPatterns.add(registeredPattern + "/");
				}
			}
		}

		String bestMatch = null;
		Comparator<String> patternComparator = getPathMatcher().getPatternComparator(urlPath);
		if (!matchingPatterns.isEmpty()) {
			matchingPatterns.sort(patternComparator);
			if (logger.isTraceEnabled() && matchingPatterns.size() > 1) {
				logger.trace("Matching patterns " + matchingPatterns);
			}
			bestMatch = matchingPatterns.get(0);
		}
		if (bestMatch != null) {
			handler = this.handlerMap.get(bestMatch);
			if (handler == null) {
				if (bestMatch.endsWith("/")) {
					handler = this.handlerMap.get(bestMatch.substring(0, bestMatch.length() - 1));
				}
				if (handler == null) {
					throw new IllegalStateException(
							"Could not find handler for best pattern match [" + bestMatch + "]");
				}
			}
			// Bean name or resolved handler?
			if (handler instanceof String) {
				String handlerName = (String) handler;
				handler = obtainApplicationContext().getBean(handlerName);
			}
			validateHandler(handler, request);
			String pathWithinMapping = getPathMatcher().extractPathWithinPattern(bestMatch, urlPath);

			// There might be multiple 'best patterns', let's make sure we have the correct URI template variables
			// for all of them
			Map<String, String> uriTemplateVariables = new LinkedHashMap<>();
			for (String matchingPattern : matchingPatterns) {
				if (patternComparator.compare(bestMatch, matchingPattern) == 0) {
					Map<String, String> vars = getPathMatcher().extractUriTemplateVariables(matchingPattern, urlPath);
					Map<String, String> decodedVars = getUrlPathHelper().decodePathVariables(request, vars);
					uriTemplateVariables.putAll(decodedVars);
				}
			}
			if (logger.isTraceEnabled() && uriTemplateVariables.size() > 0) {
				logger.trace("URI variables " + uriTemplateVariables);
			}
			//将handler封装成HandlerExecutionChain
			return buildPathExposingHandler(handler, bestMatch, pathWithinMapping, uriTemplateVariables);
		}

		// No handler found...
		return null;
	}
/*
	构造HandlerExecutionChain,封装controller
	以及2个拦截器
	 */
	protected Object buildPathExposingHandler(Object rawHandler, String bestMatchingPattern,
			String pathWithinMapping, @Nullable Map<String, String> uriTemplateVariables) {

		HandlerExecutionChain chain = new HandlerExecutionChain(rawHandler);
		chain.addInterceptor(new PathExposingHandlerInterceptor(bestMatchingPattern, pathWithinMapping));
		if (!CollectionUtils.isEmpty(uriTemplateVariables)) {
			chain.addInterceptor(new UriTemplateVariablesHandlerInterceptor(uriTemplateVariables));
		}
		return chain;
	}

没找到处理

	protected void noHandlerFound(HttpServletRequest request, HttpServletResponse response) throws Exception {
		if (pageNotFoundLogger.isWarnEnabled()) {
			pageNotFoundLogger.warn("No mapping for " + request.getMethod() + " " + getRequestUri(request));
		}
		if (this.throwExceptionIfNoHandlerFound) {
			throw new NoHandlerFoundException(request.getMethod(), getRequestUri(request),
					new ServletServerHttpRequest(request).getHeaders());
		}
		else {
			response.sendError(HttpServletResponse.SC_NOT_FOUND);
		}
	}

获取适配器

	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");
	}
	@Override
	public boolean supports(Object handler) {
		return (handler instanceof Controller);
	}

使用默认SimpleControllerHandlerAdapter

	@Override
	public boolean supports(Object handler) {
		return (handler instanceof Controller);
	}

spring5.1.x源码解析之九(spring-mvc)_第11张图片

last-modified头处理

	@Override
	public long getLastModified(HttpServletRequest request, Object handler) {
		if (handler instanceof LastModified) {
			return ((LastModified) handler).getLastModified(request);
		}
		return -1L;
	}

拦截器的调用

获取所有继承了HandlerInterceptor的类,内部分别有三个方法,分别是请求前,请求后,执行完。
spring5.1.x源码解析之九(spring-mvc)_第12张图片
DispatcherServlet#doDispatch分别执行三次
spring5.1.x源码解析之九(spring-mvc)_第13张图片
spring5.1.x源码解析之九(spring-mvc)_第14张图片
请求前调用

	boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception {
		//调用拦截器
		HandlerInterceptor[] interceptors = getInterceptors();
		if (!ObjectUtils.isEmpty(interceptors)) {
			for (int i = 0; i < interceptors.length; i++) {
				HandlerInterceptor interceptor = interceptors[i];
				if (!interceptor.preHandle(request, response, this.handler)) {
					triggerAfterCompletion(request, response, null);
					return false;
				}
				this.interceptorIndex = i;
			}
		}
		return true;
	}

返回视图

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

		return ((Controller) handler).handleRequest(request, response);
	}

	@Override
	@Nullable
	public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response)
			throws Exception {

		//对options请求方式处理
		if (HttpMethod.OPTIONS.matches(request.getMethod())) {
			response.setHeader("Allow", getAllowHeader());
			return null;
		}

		// Delegate to WebContentGenerator for checking and preparing.
		checkRequest(request);
		prepareResponse(response);

		// Execute handleRequestInternal in synchronized block if required.
		//如果需要session内的同步执行
		if (this.synchronizeOnSession) {
			HttpSession session = request.getSession(false);
			if (session != null) {
				Object mutex = WebUtils.getSessionMutex(session);
				synchronized (mutex) {
					return handleRequestInternal(request, response);
				}
			}
		}

		//调用用户逻辑
		return handleRequestInternal(request, response);
	}

异常处理

	/*
	异常处理
	页面处理
	执行拦截器执行完视图方法
	 */
	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);
			}
		}

		// 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.isTraceEnabled()) {
				logger.trace("No view rendering, null ModelAndView returned.");
			}
		}

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

		if (mappedHandler != null) {
			//请求结束调用拦截器
			mappedHandler.triggerAfterCompletion(request, response, null);
		}
	}

@Nullable
	protected ModelAndView processHandlerException(HttpServletRequest request, HttpServletResponse response,
			@Nullable Object handler, Exception ex) throws Exception {

		// Success and error responses may use different content types
		request.removeAttribute(HandlerMapping.PRODUCIBLE_MEDIA_TYPES_ATTRIBUTE);

		// Check registered HandlerExceptionResolvers...
		ModelAndView exMv = null;
		if (this.handlerExceptionResolvers != null) {
			for (HandlerExceptionResolver resolver : this.handlerExceptionResolvers) {
				//执行异常解析器并返回视图
				exMv = resolver.resolveException(request, response, handler, ex);
				if (exMv != null) {
					break;
				}
			}
		}
		if (exMv != null) {
			if (exMv.isEmpty()) {
				request.setAttribute(EXCEPTION_ATTRIBUTE, ex);
				return null;
			}
			// We might still need view name translation for a plain error model...
			if (!exMv.hasView()) {
				String defaultViewName = getDefaultViewName(request);
				if (defaultViewName != null) {
					exMv.setViewName(defaultViewName);
				}
			}
			if (logger.isTraceEnabled()) {
				logger.trace("Using resolved error view: " + exMv, ex);
			}
			if (logger.isDebugEnabled()) {
				logger.debug("Using resolved error view: " + exMv);
			}
			WebUtils.exposeErrorRequestAttributes(request, ex, getServletName());
			return exMv;
		}

		throw ex;
	}

页面处理

	/*
	解析视图
	跳转
	 */
	protected void render(ModelAndView mv, HttpServletRequest request, HttpServletResponse response) throws Exception {
		// Determine locale for request and apply it to the response.
		Locale locale =
				(this.localeResolver != null ? this.localeResolver.resolveLocale(request) : request.getLocale());
		response.setLocale(locale);

		View view;
		String viewName = mv.getViewName();
		if (viewName != null) {
			// We need to resolve the view name.
			//调用视图解析器,解析名称
			view = resolveViewName(viewName, mv.getModelInternal(), locale, request);
			if (view == null) {
				throw new ServletException("Could not resolve view with name '" + mv.getViewName() +
						"' in servlet with name '" + getServletName() + "'");
			}
		}
		else {
			// No need to lookup: the ModelAndView object contains the actual View object.
			view = mv.getView();
			if (view == null) {
				throw new ServletException("ModelAndView [" + mv + "] neither contains a view name nor a " +
						"View object in servlet with name '" + getServletName() + "'");
			}
		}

		// Delegate to the View object for rendering.
		if (logger.isTraceEnabled()) {
			logger.trace("Rendering view [" + view + "] ");
		}
		try {
			if (mv.getStatus() != null) {
				response.setStatus(mv.getStatus().value());
			}
			//页面跳转
			view.render(mv.getModelInternal(), request, response);
		}
		catch (Exception ex) {
			if (logger.isDebugEnabled()) {
				logger.debug("Error rendering view [" + view + "]", ex);
			}
			throw ex;
		}
	}

	@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) {
				View view = viewResolver.resolveViewName(viewName, locale);
				if (view != null) {
					return view;
				}
			}
		}
		return null;
	}

/*
	获取视图
	 */
	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.
						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);
						}
					}
				}
			}
			else {
				if (logger.isTraceEnabled()) {
					logger.trace(formatKey(cacheKey) + "served from cache");
				}
			}
			return (view != UNRESOLVED_VIEW ? view : null);
		}
	}

	@Nullable
	protected View createView(String viewName, Locale locale) throws Exception {
		//子类实现,主要添加前后缀之内的
		return loadView(viewName, locale);
	}
	/*
	对redirect,forward前缀支持
	添加url前后缀
	生成view,并添加必要属性
	 */
	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 view = new RedirectView(redirectUrl,
					isRedirectContextRelative(), isRedirectHttp10Compatible());
			String[] hosts = getRedirectHosts();
			if (hosts != null) {
				view.setHosts(hosts);
			}
			return applyLifecycleMethods(REDIRECT_URL_PREFIX, view);
		}

		// Check for special "forward:" prefix.
		//处理前缀为forward:
		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);
		}

		// Else fall back to superclass implementation: calling loadView.
		//本类实现方法,主要实现了url前后缀添加以及其他属性
		return super.createView(viewName, locale);
	}
	@Nullable
	protected View createView(String viewName, Locale locale) throws Exception {
		//子类实现,主要添加前后缀之内的
		return loadView(viewName, locale);
	}
	@Override
	protected View loadView(String viewName, Locale locale) throws Exception {
		//设置前后缀
		AbstractUrlBasedView view = buildView(viewName);
		View result = applyLifecycleMethods(viewName, view);
		return (view.checkResource(locale) ? result : null);
	}

页面跳转

/*
	封装数据
	子类实现扩展
	处理页面跳转
	 */
	public void render(@Nullable Map<String, ?> model, HttpServletRequest request,
			HttpServletResponse response) throws Exception {

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

		//封装页面所需数据
		Map<String, Object> mergedModel = createMergedOutputModel(model, request, response);
		//子类实现扩展
		prepareResponse(request, response);
		//处理页面跳转
		renderMergedOutputModel(mergedModel, getRequestToExpose(request), response);
	}

/*
	执行转发或包含
	 */
	protected void renderMergedOutputModel(
			Map<String, Object> model, HttpServletRequest request, HttpServletResponse response) throws Exception {

		// Expose the model object as request attributes.
		//model存request
		exposeModelAsRequestAttributes(model, request);

		// Expose helpers as request attributes, if any.
		exposeHelpers(request);

		// Determine the path for the request dispatcher.
		//确定路径,避免浏览器路径和返回路径一致
		String dispatcherPath = prepareForRendering(request, response);

		// Obtain a RequestDispatcher for the target resource (typically a JSP).
		RequestDispatcher rd = getRequestDispatcher(request, dispatcherPath);
		if (rd == null) {
			throw new ServletException("Could not get RequestDispatcher for [" + getUrl() +
					"]: Check that the corresponding file exists within your web application archive!");
		}

		// If already included or response already committed, perform include, else forward.
		//如果已经包含或响应已经提交,则执行include,否则转发。
		if (useInclude(request, response)) {
			response.setContentType(getContentType());
			if (logger.isDebugEnabled()) {
				logger.debug("Including [" + getUrl() + "]");
			}
			rd.include(request, response);
		}

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

你可能感兴趣的:(spring源码)