一、Spring父容器启动
SpringMVC 的项目结构如下:
applicationContext.xml spring的配置文件
<?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/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/contexthttps://www.springframework.org/schema/context/spring-context.xsdhttp://www.springframework.org/schema/mvchttps://www.springframework.org/schema/mvc/spring-mvc.xsd"><context:component-scan base-package="com.mashibing"></context:component-scan><bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver"><property name="suffix" value=".jsp"></property><property name="prefix" value="/WEB-INF/jsp/"></property></bean>
</beans>
spring-config.xml SpringMVC 配置文件
<?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 id = "user" class="com.mashibing.bean.User"><property name="username" value="zhangsan"></property><property name="age" value="12"></property></bean>
</beans>
web.xml该配置文件是在tomcat启动的时候加载的
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"version="4.0"><context-param><param-name>contextConfigLocation</param-name><param-value>classpath:spring-config.xml</param-value></context-param><!--Spring加载的配置文件--><servlet><servlet-name>mvc-test</servlet-name><servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class><!--Springmvc加载启动是放在servlet中执行的 servlet的生命周期 init在HttpServletBean service destory--><!--SpringMVC配置文件--><init-param><param-name>contextConfigLocation</param-name><param-value>classpath:applicationContext.xml</param-value></init-param><load-on-startup>1</load-on-startup><async-supported>true</async-supported></servlet><servlet-mapping><servlet-name>mvc-test</servlet-name><url-pattern>/</url-pattern></servlet-mapping><listener><listener-class>org.springframework.web.context.ContextLoaderListener</listener-class></listener><!--监听器 方法的入口 这里是tomcat调用的 -->
</web-app><!--配置文件可写监听器 过滤器这些 springmvc是基于spring进行扩展 启动springmvc之前先把spring启动起来 先启动tomcat容器 -->
ContextLoaderListener 的初始化和实例化是tomcat容器加载web.xml文件的时候完成的,ContextLoaderListener 类下的contextInitialized初始化根web应用程序上下文。
spring是父容器和springmvc子容器两个容器的作用是为了数据的隔离,子容器有parentFactory
此链路执行开始初始化web.xml文件的监听器listener类ContextLoaderListener
<init>:56, ContextLoaderListener (org.springframework.web.context)
newInstance0:-1, NativeConstructorAccessorImpl (sun.reflect)
newInstance:62, NativeConstructorAccessorImpl (sun.reflect)
newInstance:45, DelegatingConstructorAccessorImpl (sun.reflect)
newInstance:423, Constructor (java.lang.reflect)
newInstance:150, DefaultInstanceManager (org.apache.catalina.core)
listenerStart:4691, StandardContext (org.apache.catalina.core)
startInternal:5230, StandardContext (org.apache.catalina.core)
start:183, LifecycleBase (org.apache.catalina.util)
addChildInternal:726, ContainerBase (org.apache.catalina.core)
addChild:698, ContainerBase (org.apache.catalina.core)
addChild:696, StandardHost (org.apache.catalina.core)
manageApp:1783, HostConfig (org.apache.catalina.startup)
invoke0:-1, NativeMethodAccessorImpl (sun.reflect)
invoke:62, NativeMethodAccessorImpl (sun.reflect)
invoke:43, DelegatingMethodAccessorImpl (sun.reflect)
invoke:498, Method (java.lang.reflect)
invoke:293, BaseModelMBean (org.apache.tomcat.util.modeler)
invoke:819, DefaultMBeanServerInterceptor (com.sun.jmx.interceptor)
invoke:801, JmxMBeanServer (com.sun.jmx.mbeanserver)
createStandardContext:460, MBeanFactory (org.apache.catalina.mbeans)
createStandardContext:408, MBeanFactory (org.apache.catalina.mbeans)
invoke0:-1, NativeMethodAccessorImpl (sun.reflect)
invoke:62, NativeMethodAccessorImpl (sun.reflect)
invoke:43, DelegatingMethodAccessorImpl (sun.reflect)
invoke:498, Method (java.lang.reflect)
invoke:293, BaseModelMBean (org.apache.tomcat.util.modeler)
invoke:819, DefaultMBeanServerInterceptor (com.sun.jmx.interceptor)
invoke:801, JmxMBeanServer (com.sun.jmx.mbeanserver)
invoke:468, MBeanServerAccessController (com.sun.jmx.remote.security)
doOperation:1468, RMIConnectionImpl (javax.management.remote.rmi)
access$300:76, RMIConnectionImpl (javax.management.remote.rmi)
run:1309, RMIConnectionImpl$PrivilegedOperation (javax.management.remote.rmi)
doPrivileged:-1, AccessController (java.security)
doPrivilegedOperation:1408, RMIConnectionImpl (javax.management.remote.rmi)
invoke:829, RMIConnectionImpl (javax.management.remote.rmi)
invoke0:-1, NativeMethodAccessorImpl (sun.reflect)
invoke:62, NativeMethodAccessorImpl (sun.reflect)
invoke:43, DelegatingMethodAccessorImpl (sun.reflect)
invoke:498, Method (java.lang.reflect)
dispatch:346, UnicastServerRef (sun.rmi.server)
run:200, Transport$1 (sun.rmi.transport)
run:197, Transport$1 (sun.rmi.transport)
doPrivileged:-1, AccessController (java.security)
serviceCall:196, Transport (sun.rmi.transport)
handleMessages:568, TCPTransport (sun.rmi.transport.tcp)
run0:826, TCPTransport$ConnectionHandler (sun.rmi.transport.tcp)
lambda$run$0:683, TCPTransport$ConnectionHandler (sun.rmi.transport.tcp)
run:-1, 393312068 (sun.rmi.transport.tcp.TCPTransport$ConnectionHandler$$Lambda$25)
doPrivileged:-1, AccessController (java.security)
run:682, TCPTransport$ConnectionHandler (sun.rmi.transport.tcp)
runWorker:1142, ThreadPoolExecutor (java.util.concurrent)
run:617, ThreadPoolExecutor$Worker (java.util.concurrent)
run:748, Thread (java.lang)
调用ContextLoaderListener构造函数
监听事件开始执行,初始化根web应用程序上下文。
event.getServletContext()的结果:包含web.xml文件的contextConfigLocation
<context-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:spring-config.xml</param-value> </context-param>
,获取到spring需要的配置文件,接下来开始执行spring容器的启动
ContextLoader##initWebApplicationContext
/*** Initialize Spring's web application context for the given servlet context,为给定的servlet上下文初始化Spring的web应用程序上下文。* using the application context provided at construction time, or creating a new one使用在构造时提供的应用程序上下文,* according to the "{@link #CONTEXT_CLASS_PARAM contextClass}" and 或根据“{@link CONTEXT_CLASS_PARAM contextClass}”和“{@link CONFIG_LOCATION_PARAM contextConfigLocation}”上下文参数创建一个新上下文。* "{@link #CONFIG_LOCATION_PARAM contextConfigLocation}" context-params.* @param servletContext current servlet context* @return the new WebApplicationContext* @see #ContextLoader(WebApplicationContext)* @see #CONTEXT_CLASS_PARAM* @see #CONFIG_LOCATION_PARAM*/public WebApplicationContext initWebApplicationContext(ServletContext servletContext) {if (servletContext.getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE) != null) {// web.xml中存在多次ContextLoader定义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) {//this是代指监听器 第一进去是null// 初始化context,第一次执行的时候获取到一个root webApplicationcontext 是在XmlWebApplicationContext的父类AbstractRefreshableWebApplicationContext构造方法setDisplayName中赋值为root webApplicationcontextthis.context = createWebApplicationContext(servletContext);}if (this.context instanceof ConfigurableWebApplicationContext) {ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext) this.context;if (!cwac.isActive()) {//判断是否激活 上下文尚未刷新->提供诸如设置父上下文、设置应用程序上下文id等服务// The context has not yet been refreshed -> provide services such as// setting the parent context, setting the application context id, etcif (cwac.getParent() == null) {// The context instance was injected without an explicit parent -> context实例被注入时没有显式的父元素->// determine parent for root web application context, if any. 确定web应用程序根上下文的父元素(如果有的话)。ApplicationContext parent = loadParentContext(servletContext);cwac.setParent(parent);//子类容器也会调用 会把父容器设置进去的}configureAndRefreshWebApplicationContext(cwac, servletContext);//refresh刷新}}// 将创建的context对象记录在servletContext中,创建并且准备好了spring容器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;//IOC容器准备好勒 原生自带的spring容器}catch (RuntimeException | Error ex) {logger.error("Context initialization failed", ex);servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, ex);throw ex;}}
createWebApplicationContext
初始化context,第一次执行的时候获取到一个root webApplicationcontext 是在XmlWebApplicationContext的父类AbstractRefreshableWebApplicationContext构造方法setDisplayName中赋值displayName为root webApplicationcontext
protected WebApplicationContext createWebApplicationContext(ServletContext sc) {// 获取contextClass的Class对象Class<?> contextClass = determineContextClass(sc);// 如果是自定义的contextClass对象,那么必须要实现ConfigurableWebApplicationContext此接口,否则无法直接运行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);//进行实例化}
XmlWebApplicationContext类图:
initWebApplicationContext方法的loadParentContext:确定web应用程序根上下文的父元素(如果有的话)。子容器启动的时候会获取到父类放置进去
ContextLoader的configureAndRefreshWebApplicationContext
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 应用程序上下文id仍然设置为其原始默认值// -> assign a more useful id based on available information 根据可用信息分配一个更有用的idString idParam = sc.getInitParameter(CONTEXT_ID_PARAM);//CONTEXT_ID_PARAM=contextIdif (idParam != null) {wac.setId(idParam);}else {// Generate default id... 生成唯一标识wac.setId(ConfigurableWebApplicationContext.APPLICATION_CONTEXT_ID_PREFIX +ObjectUtils.getDisplayString(sc.getContextPath()));}}wac.setServletContext(sc);//String configLocationParam = sc.getInitParameter(CONFIG_LOCATION_PARAM);//web.xml文件配置的 contextConfigLocation = classpath:spring-config.xmlif (configLocationParam != null) {wac.setConfigLocation(configLocationParam);//设置要加载的spring配置文件}//当上下文被刷新时,wac环境的initpropertsources将在任何情况下被调用;在这里急切地确保servlet属性源在任何后处理或在刷新之前发生的初始化中使用// 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 #refreshConfigurableEnvironment env = wac.getEnvironment();if (env instanceof ConfigurableWebEnvironment) {//将基于{@code Servlet}的{@link StubPropertySource存根属性源}替换为使用给定的{@code servletContext}和{@code servletConfig}对象填充的实际实例。<p>此方法是幂等的,因为它可以被调用任意次数,但将用相应的实际属性源执行一次且仅一次的存根属性源替换。((ConfigurableWebEnvironment) env).initPropertySources(sc, null);}customizeContext(sc, wac);//定制beanFactory,设置相关属性,包括是否允许覆盖同名称的不同定义的对象以及循环依赖 wac.refresh()#refresh#obtainFreshBeanFactory#refreshBeanFactorywac.refresh();//AbstractApplicationContext里执行调用 这步执行之后 spring容器启动成功}
读取到spring加载需要的配置文件 准备执行spring的刷新方法
wac.refresh();AbstractApplicationContext里执行调用 这步执行之后 spring容器启动成功
postProcessBeanFactory(beanFactory);//spring项目没实现 在springMvc中启动spring会有 AbstractRefreshableWebApplicationContext 实现类finishRefresh(); 完成刷新过程,通知生命周期处理器lifecycleProcessor刷新过程,同时发出ContextRefreshEvent通知别人,下面的publishEvent方法 将给定事件发布到所有监听器
wac.refresh执行结束之后可以看到spring配置文件的配置的bean标签被假造到一级缓存对象中去
user对象实例化初始化结束了
后续将创建的context对象记录在servletContext中,创建并且准备好了spring容器
至此spring容器启动完成,接下来开始加载springmvc容器。
二、SpringMVC子容器加载
SpringMVC是严格尊重servlet的生命周期的,初始化就是在init方法中。
<servlet><servlet-name>mvc-test</servlet-name><servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class><!--Springmvc加载启动是放在servlet中执行的 servlet的生命周期 init在HttpServletBean service destory--><!--SpringMVC配置文件--><init-param><param-name>contextConfigLocation</param-name><param-value>classpath:applicationContext.xml</param-value></init-param><load-on-startup>1</load-on-startup><async-supported>true</async-supported></servlet>
servlet相关的类图如下:HttpServletBean的加载实例化初始化时在tomcat容器中进行完成的
init
/*** Map config parameters onto bean properties of this servlet 将配置参数映射到这个servlet的bean属性上,* , and invoke subclass initialization.并调用子类初始化。* @throws ServletException if bean properties are invalid (or required* properties are missing), or if subclass initialization fails.如果bean属性无效(或者缺少必需的属性),或者子类初始化失败。*/@Overridepublic final void init() throws ServletException {//该方法是在tomcat 容器中调用的// Set bean properties from init parameters.// 将servlet中配置的init-param参数封装到pvs变量中 contextConfigLocation:classpath:applicationContext.xmlPropertyValues pvs = new ServletConfigPropertyValues(getServletConfig(), this.requiredProperties);if (!pvs.isEmpty()) {try {// 将当前的servlet对象转化成BeanWrapper对象,从而能够以spring的方法来将pvs注入到该beanWrapper中BeanWrapper bw = PropertyAccessorFactory.forBeanPropertyAccess(this);//this是DispatcherServletResourceLoader resourceLoader = new ServletContextResourceLoader(getServletContext());// 注册自定义属性编辑器,一旦有Resource类型的属性,将会使用ResourceEditor进行解析bw.registerCustomEditor(Resource.class, new ResourceEditor(resourceLoader, getEnvironment()));// 模板方法,可以在子类调用,做一些初始化工作,bw代表的是DispatcherServletinitBeanWrapper(bw);// 以spring的方式来将pvs注入到该beanWrapper对象中,将配置的初始化值(contextConfigLocation)设置到DispatcherServletbw.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.// 模板方法,子类初始化的入口方法,查看FrameworkServlet#initServletBean方法initServletBean();}
进入FrameworkServlet类的initServletBean方法
FrameworkServlet类下的initServletBean
/**{@link HttpServletBean}的重写方法,在任何bean属性设置后调用。创建这个servlet的WebApplicationContext。* Overridden method of {@link HttpServletBean}, invoked after any bean properties* have been set. Creates this servlet's WebApplicationContext.*/@Overrideprotected 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 {// 创建或刷新WebApplicationContext实例并对servlet功能所使用的变量进行初始化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");}}
FrameworkServlet类initWebApplicationContext方法
/*** 此处同学们需要知道一个原理,所有的前后端交互的框架都是以servlet为基础的,所以在使用springmvc的时候,默认会把自己的容器设置成ServletContext* 的属性,默认根容器的key为WebApplicaitonContext.Root,定义在WebApplicationContext中,所以在获取的时候只需要调用ServletContext.getAttribute即可*** Initialize and publish the WebApplicationContext for this servlet.* <p>Delegates to {@link #createWebApplicationContext} for actual creation* of the context. Can be overridden in subclasses.* @return the WebApplicationContext instance* @see #FrameworkServlet(WebApplicationContext)* @see #setContextClass* @see #setContextConfigLocation*/protected WebApplicationContext initWebApplicationContext() {// 获得根webApplicationContext对象WebApplicationContext rootContext =WebApplicationContextUtils.getWebApplicationContext(getServletContext());// 获得webApplicationContext wac对象WebApplicationContext wac = null;// 如果构造方法中已经传入webApplicationContext属性,则直接使用// 此方式主要用于servlet3.0之后的环境,也就是说可以通过ServletContext.addServlet的方法注册servlet,此时就可以在创建FrameworkServlet和// 其子类的时候通过构造方法传递已经准备好的webApplicationContextif (this.webApplicationContext != null) {// A context instance was injected at construction time 在构造时注入了上下文实例 -> use itwac = this.webApplicationContext;// 如果是ConfigurationWebApplicationContext类型,并且未激活,则进行初始化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, etcif (cwac.getParent() == null) {// The context instance was injected without an explicit parent -> set// the root application context (if any; may be null) as the parentcwac.setParent(rootContext);}// 配置和刷新上下文环境configureAndRefreshWebApplicationContext(cwac);}}}// 从servletContext获取对应的webApplicationContext对象// 此方式需要在配置Servlet的时候将servletContext中的webApplicationContext的name配置到contextAttribute属性就可以/*<servlet><servlet-name>mvc-test</servlet-name><servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class><!--SpringMVC配置文件--><init-param><param-name>contextAttribute</param-name><param-value>mashibing</param-value></init-param><load-on-startup>1</load-on-startup></servlet>*/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 idwac = findWebApplicationContext();}// 当前面两种方式都无效的情况下会创建一个webApplicationContext对象,一般情况下都是使用这样的方式if (wac == null) {// No context instance is defined for this servlet -> create a local onewac = createWebApplicationContext(rootContext);}// 将contextRefreshedEvent事件没有触发时调用此方法,模板方法,可以在子类重写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) {onRefresh(wac);}}// 将applicationContext设置到servletContext中if (this.publishContext) {// Publish the context as a servlet context attribute.String attrName = getServletContextAttributeName();getServletContext().setAttribute(attrName, wac);}return wac;}
这里把spring容器设置为springmvc的父容器,看parent的一级缓存有spring配置文件的bean标签实例化的对象就可以知道了
ServletContext servlet的上下文对象,包含整个web.xml文件的配置
ServletConfig 被某个servlet持有,对应的servlet中的配置属性
添加监听器以及对应监听器的监听的事件类型
添加监听器sourceFilteringListener到wac中,实际监听的是ContextRefreshListener所监听的事件,监听ContextRefreshedEvent事件
当接收到消息之后会调用onApplicationEvent方法,调用onRefresh方法,并将refreshEventReceived标志设置为true,表示已经refresh过
this.applicationListeners.add(listener);AbstractApplicationContext的applicationListeners集合有了一个监听器
ContextRefreshListener
/*** Callback that receives refresh events from this servlet's WebApplicationContext.从servlet的WebApplicationContext接收刷新事件的回调* <p>The default implementation calls {@link #onRefresh},* triggering a refresh of this servlet's context-dependent state.默认的实现调用{@link onRefresh},触发这个servlet的上下文依赖状态的刷新。* @param event the incoming ApplicationContext event 传入的ApplicationContext事件*/public void onApplicationEvent(ContextRefreshedEvent event) {// 标记 refreshEventReceived 为truethis.refreshEventReceived = true;synchronized (this.onRefreshMonitor) {// 处理事件中的 ApplicationContext 对象,空实现,子类DispatcherServlet会实现onRefresh(event.getApplicationContext());}}
**wac.refresh();**开始刷新wac,从而初始化wac,现在完成SpringMVC的容器创建,加载配置文件生成对象
@Overridepublic void refresh() throws BeansException, IllegalStateException {synchronized (this.startupShutdownMonitor) {// Prepare this context for refreshing./*** 前戏,做容器刷新前的准备工作* 1、设置容器的启动时间* 2、设置活跃状态为true* 3、设置关闭状态为false* 4、获取Environment对象,并加载当前系统的属性值到Environment对象中* 5、准备监听器和事件的集合对象,默认为空的集合*/prepareRefresh();// Tell the subclass to refresh the internal bean factory. 告诉子类刷新内部bean工厂。// 创建容器对象:DefaultListableBeanFactory// 加载xml配置文件的属性值到当前工厂中,最重要的就是BeanDefinitionConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();// Prepare the bean factory for use in this context.// beanFactory的准备工作,对各种属性进行填充prepareBeanFactory(beanFactory);try {// Allows post-processing of the bean factory in context subclasses.// 子类覆盖方法做额外的处理,此处我们自己一般不做任何扩展工作,但是可以查看web中的代码,是有具体实现的postProcessBeanFactory(beanFactory);//spring项目没实现 在springMvc中启动spring会有 AbstractRefreshableWebApplicationContext 实现类// Invoke factory processors registered as beans in the context.// 调用各种beanFactory处理器invokeBeanFactoryPostProcessors(beanFactory);// Register bean processors that intercept bean creation.// 注册bean处理器,这里只是注册功能,真正调用的是getBean方法registerBeanPostProcessors(beanFactory);// Initialize message source for this context.// 为上下文初始化message源,即不同语言的消息体,国际化处理,在springmvc的时候通过国际化的代码重点讲initMessageSource();// Initialize event multicaster for this context.// 初始化事件监听多路广播器initApplicationEventMulticaster();// Initialize other special beans in specific context subclasses.// 留给子类来初始化其他的beanonRefresh();//AbstractRefreshableWebApplicationContext 实现了// Check for listener beans and register them.// 在所有注册的bean中查找listener bean,注册到消息广播器中registerListeners();// Instantiate all remaining (non-lazy-init) singletons.// 初始化剩下的单实例(非懒加载的)finishBeanFactoryInitialization(beanFactory);// Last step: publish corresponding event.// 完成刷新过程,通知生命周期处理器lifecycleProcessor刷新过程,同时发出ContextRefreshEvent通知别人finishRefresh();}catch (BeansException ex) {if (logger.isWarnEnabled()) {logger.warn("Exception encountered during context initialization - " +"cancelling refresh attempt: " + ex);}// Destroy already created singletons to avoid dangling resources.// 为防止bean资源占用,在异常处理中,销毁已经在前面过程中生成的单件beandestroyBeans();// Reset 'active' flag.// 重置active标志cancelRefresh(ex);// Propagate exception to caller.throw ex;}finally {// Reset common introspection caches in Spring's core, since we// might not ever need metadata for singleton beans anymore...resetCommonCaches();}}}
refresh方法调用finishRefresh();
完成刷新过程,通知生命周期处理器lifecycleProcessor刷新过程,同时发出ContextRefreshEvent通知别人
protected void finishRefresh() {// Clear context-level resource caches (such as ASM metadata from scanning).// 清除上下文级别的资源缓存(如扫描的ASM元数据)// 清空在资源加载器中的所有资源缓存clearResourceCaches();// Initialize lifecycle processor for this context.// 为这个上下文初始化生命周期处理器// 初始化LifecycleProcessor.如果上下文中找到'lifecycleProcessor'的LifecycleProcessor Bean对象,// 则使用DefaultLifecycleProcessorinitLifecycleProcessor();// Propagate refresh to lifecycle processor first.// 首先将刷新传播到生命周期处理器// 上下文刷新的通知,例如自动启动的组件getLifecycleProcessor().onRefresh();// Publish the final event.// 发布最终事件// 新建ContextRefreshedEvent事件对象,将其发布到所有监听器。publishEvent(new ContextRefreshedEvent(this));// Participate in LiveBeansView MBean, if active.// 参与LiveBeansView MBean,如果是活动的// LiveBeansView:Sping用于支持JMX 服务的类// 注册当前上下文到LiveBeansView,以支持JMX服务LiveBeansView.registerApplicationContext(this);}
initStrategies是初始化springMVC内置组件的方法,先贴出调用的方法轨迹:
publishEvent发布最终事件开始,一直到调用initStrategies,都是监听器相关
initStrategies:523, DispatcherServlet (org.springframework.web.servlet)
onRefresh:514, DispatcherServlet (org.springframework.web.servlet)
onApplicationEvent:901, FrameworkServlet (org.springframework.web.servlet)
onApplicationEvent:1277, FrameworkServlet$ContextRefreshListener (org.springframework.web.servlet)
onApplicationEvent:1273, FrameworkServlet$ContextRefreshListener (org.springframework.web.servlet)
onApplicationEvent:64, GenericApplicationListenerAdapter (org.springframework.context.event)
onApplicationEventInternal:109, SourceFilteringListener (org.springframework.context.event)
onApplicationEvent:73, SourceFilteringListener (org.springframework.context.event)
doInvokeListener:215, SimpleApplicationEventMulticaster (org.springframework.context.event)
invokeListener:202, SimpleApplicationEventMulticaster (org.springframework.context.event)
multicastEvent:164, SimpleApplicationEventMulticaster (org.springframework.context.event)
publishEvent:440, AbstractApplicationContext (org.springframework.context.support)
publishEvent:379, AbstractApplicationContext (org.springframework.context.support)
finishRefresh:1053, AbstractApplicationContext (org.springframework.context.support)
refresh:618, AbstractApplicationContext (org.springframework.context.support)
configureAndRefreshWebApplicationContext:759, FrameworkServlet (org.springframework.web.servlet)
createWebApplicationContext:715, FrameworkServlet (org.springframework.web.servlet)
createWebApplicationContext:773, FrameworkServlet (org.springframework.web.servlet)
initWebApplicationContext:625, FrameworkServlet (org.springframework.web.servlet)
initServletBean:536, FrameworkServlet (org.springframework.web.servlet)
init:185, HttpServletBean (org.springframework.web.servlet)
init:158, GenericServlet (javax.servlet)
initServlet:1164, StandardWrapper (org.apache.catalina.core)
loadServlet:1117, StandardWrapper (org.apache.catalina.core)
load:1010, StandardWrapper (org.apache.catalina.core)
loadOnStartup:4957, StandardContext (org.apache.catalina.core)
startInternal:5264, StandardContext (org.apache.catalina.core)
start:183, LifecycleBase (org.apache.catalina.util)
addChildInternal:726, ContainerBase (org.apache.catalina.core)
addChild:698, ContainerBase (org.apache.catalina.core)
addChild:696, StandardHost (org.apache.catalina.core)
manageApp:1783, HostConfig (org.apache.catalina.startup)
invoke0:-1, NativeMethodAccessorImpl (sun.reflect)
invoke:62, NativeMethodAccessorImpl (sun.reflect)
invoke:43, DelegatingMethodAccessorImpl (sun.reflect)
invoke:498, Method (java.lang.reflect)
invoke:293, BaseModelMBean (org.apache.tomcat.util.modeler)
invoke:819, DefaultMBeanServerInterceptor (com.sun.jmx.interceptor)
invoke:801, JmxMBeanServer (com.sun.jmx.mbeanserver)
createStandardContext:460, MBeanFactory (org.apache.catalina.mbeans)
createStandardContext:408, MBeanFactory (org.apache.catalina.mbeans)
invoke0:-1, NativeMethodAccessorImpl (sun.reflect)
invoke:62, NativeMethodAccessorImpl (sun.reflect)
invoke:43, DelegatingMethodAccessorImpl (sun.reflect)
invoke:498, Method (java.lang.reflect)
invoke:293, BaseModelMBean (org.apache.tomcat.util.modeler)
invoke:819, DefaultMBeanServerInterceptor (com.sun.jmx.interceptor)
invoke:801, JmxMBeanServer (com.sun.jmx.mbeanserver)
invoke:468, MBeanServerAccessController (com.sun.jmx.remote.security)
doOperation:1468, RMIConnectionImpl (javax.management.remote.rmi)
access$300:76, RMIConnectionImpl (javax.management.remote.rmi)
run:1309, RMIConnectionImpl$PrivilegedOperation (javax.management.remote.rmi)
doPrivileged:-1, AccessController (java.security)
doPrivilegedOperation:1408, RMIConnectionImpl (javax.management.remote.rmi)
invoke:829, RMIConnectionImpl (javax.management.remote.rmi)
invoke0:-1, NativeMethodAccessorImpl (sun.reflect)
invoke:62, NativeMethodAccessorImpl (sun.reflect)
invoke:43, DelegatingMethodAccessorImpl (sun.reflect)
invoke:498, Method (java.lang.reflect)
dispatch:346, UnicastServerRef (sun.rmi.server)
run:200, Transport$1 (sun.rmi.transport)
run:197, Transport$1 (sun.rmi.transport)
doPrivileged:-1, AccessController (java.security)
serviceCall:196, Transport (sun.rmi.transport)
handleMessages:568, TCPTransport (sun.rmi.transport.tcp)
run0:826, TCPTransport$ConnectionHandler (sun.rmi.transport.tcp)
lambda$run$0:683, TCPTransport$ConnectionHandler (sun.rmi.transport.tcp)
run:-1, 1102395047 (sun.rmi.transport.tcp.TCPTransport$ConnectionHandler$$Lambda$25)
doPrivileged:-1, AccessController (java.security)
run:682, TCPTransport$ConnectionHandler (sun.rmi.transport.tcp)
runWorker:1142, ThreadPoolExecutor (java.util.concurrent)
run:617, ThreadPoolExecutor$Worker (java.util.concurrent)
run:748, Thread (java.lang)
三、SpringMVC 9大内置组件开始进行初始化
initStrategies初始化
/**初始化* Initialize the strategy objects that this servlet uses.* <p>May be overridden in subclasses in order to initialize further strategy objects.*/protected void initStrategies(ApplicationContext context) {// 初始化 MultipartResolver:主要用来处理文件上传.如果定义过当前类型的bean对象,那么直接获取,如果没有的话,可以为nullinitMultipartResolver(context);// 初始化 LocaleResolver:主要用来处理国际化配置,基于URL参数的配置(AcceptHeaderLocaleResolver),基于session的配置(SessionLocaleResolver),基于cookie的配置(CookieLocaleResolver)initLocaleResolver(context);// 初始化 ThemeResolver:主要用来设置主题ThemeinitThemeResolver(context);// 初始化 HandlerMapping:映射器,用来将对应的request跟controller进行对应initHandlerMappings(context);// 初始化 HandlerAdapter:处理适配器,主要包含Http请求处理器适配器,简单控制器处理器适配器,注解方法处理器适配器initHandlerAdapters(context);// 初始化 HandlerExceptionResolver:基于HandlerExceptionResolver接口的异常处理initHandlerExceptionResolvers(context);// 初始化 RequestToViewNameTranslator:当controller处理器方法没有返回一个View对象或逻辑视图名称,并且在该方法中没有直接往response的输出流里面写数据的时候,spring将会采用约定好的方式提供一个逻辑视图名称initRequestToViewNameTranslator(context);// 初始化 ViewResolver: 将ModelAndView选择合适的视图进行渲染的处理器initViewResolvers(context);// 初始化 FlashMapManager: 提供请求存储属性,可供其他请求使用initFlashMapManager(context);}
1.初始化 MultipartResolver:主要用来处理文件上传
初始化 MultipartResolver:主要用来处理文件上传.如果定义过当前类型的bean对象,那么直接获取,如果没有的话,可以为null
initMultipartResolver(context);
/*** Initialize the MultipartResolver used by this class. 初始化该类使用的MultipartResolver。* <p>If no bean is defined with the given name in the BeanFactory for this namespace, 如果在BeanFactory中没有为这个名称空间定义带有给定名称的bean,* no multipart handling is provided. 不提供多部分处理。*/private void initMultipartResolver(ApplicationContext context) {try {// 从spring上下文获取名称为 multipartResolver ,类型为MultipartResolver的Bean 实现multipartResolver接口 可以自己定义上传文件组件 本web.xml文件没有自定义 所以此处获取不到的this.multipartResolver = context.getBean(MULTIPART_RESOLVER_BEAN_NAME, MultipartResolver.class);//multipartResolverif (logger.isTraceEnabled()) {logger.trace("Detected " + this.multipartResolver);}else if (logger.isDebugEnabled()) {logger.debug("Detected " + this.multipartResolver.getClass().getSimpleName());}}catch (NoSuchBeanDefinitionException ex) {// Default is no multipart resolver.this.multipartResolver = null;if (logger.isTraceEnabled()) {logger.trace("No MultipartResolver '" + MULTIPART_RESOLVER_BEAN_NAME + "' declared");}}}
2.初始化 LocaleResolver:主要用来处理国际化配置
初始化 LocaleResolver:主要用来处理国际化配置,基于URL参数的配置(AcceptHeaderLocaleResolver),基于session的配置(SessionLocaleResolver),基于cookie的配置(CookieLocaleResolver)initLocaleResolver(context);
private void initLocaleResolver(ApplicationContext context) {try {// 从上下文中获取Bean名称为 LocaleResolver的对象this.localeResolver = context.getBean(LOCALE_RESOLVER_BEAN_NAME, LocaleResolver.class);//localeResolver 进行国际化相关处理if (logger.isTraceEnabled()) {logger.trace("Detected " + this.localeResolver);}else if (logger.isDebugEnabled()) {logger.debug("Detected " + this.localeResolver.getClass().getSimpleName());}}catch (NoSuchBeanDefinitionException ex) {// We need to use the default.// 从配置文件中获取默认的AcceptHeaderLocaleResolver对象this.localeResolver = getDefaultStrategy(context, LocaleResolver.class);if (logger.isTraceEnabled()) {logger.trace("No LocaleResolver '" + LOCALE_RESOLVER_BEAN_NAME +"': using default [" + this.localeResolver.getClass().getSimpleName() + "]");}}}
protected <T> T getDefaultStrategy(ApplicationContext context, Class<T> strategyInterface) {List<T> strategies = getDefaultStrategies(context, strategyInterface);if (strategies.size() != 1) {throw new BeanInitializationException("DispatcherServlet needs exactly 1 strategy for interface [" + strategyInterface.getName() + "]");}return strategies.get(0);}
/*** Create a List of default strategy objects for the given strategy interface.* <p>The default implementation uses the "DispatcherServlet_test.properties" file (in the same* package as the DispatcherServlet class) to determine the class names. It instantiates* the strategy objects through the context's BeanFactory.* @param context the current WebApplicationContext* @param strategyInterface the strategy interface* @return the List of corresponding strategy objects*/@SuppressWarnings("unchecked")protected <T> List<T> getDefaultStrategies(ApplicationContext context, Class<T> strategyInterface) {// 获得strategyInterface对应的value值String key = strategyInterface.getName();// 创建value对应的对象们,并返回String value = defaultStrategies.getProperty(key);if (value != null) {// 基于","分隔,创建classNames数组String[] classNames = StringUtils.commaDelimitedListToStringArray(value);// 创建strategyInterface集合List<T> strategies = new ArrayList<>(classNames.length);// 遍历classNames数组,创建对应的类,添加到strategyInterface中for (String className : classNames) {try {// 获得className类Class<?> clazz = ClassUtils.forName(className, DispatcherServlet.class.getClassLoader());// 创建className对应的类,并添加到strategies中Object strategy = createDefaultStrategy(context, clazz);strategies.add((T) strategy);}catch (ClassNotFoundException ex) {throw new BeanInitializationException("Could not find DispatcherServlet's default strategy class [" + className +"] for interface [" + key + "]", ex);}catch (LinkageError err) {throw new BeanInitializationException("Unresolvable class definition for DispatcherServlet's default strategy class [" +className + "] for interface [" + key + "]", err);}}return strategies;}else {return new LinkedList<>();}}
defaultStrategies的初始化是在:这个静态代码块
DEFAULT_STRATEGIES_PATH类路径资源的名称(相对于DispatcherServlet类),它定义了DispatcherServlet的默认策略名称。
private static final String DEFAULT_STRATEGIES_PATH = “DispatcherServlet_test.properties”;
DispatcherServlet_test.properties
# Default implementation classes for DispatcherServlet's strategy interfaces.
# Used as fallback when no matching beans are found in the DispatcherServlet context.
# Not meant to be customized by application developers.org.springframework.web.servlet.LocaleResolver=org.springframework.web.servlet.i18n.AcceptHeaderLocaleResolverorg.springframework.web.servlet.ThemeResolver=org.springframework.web.servlet.theme.FixedThemeResolverorg.springframework.web.servlet.HandlerMapping=org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping,\org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping,\org.springframework.web.servlet.function.support.RouterFunctionMappingorg.springframework.web.servlet.HandlerAdapter=org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter,\org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter,\org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter,\org.springframework.web.servlet.function.support.HandlerFunctionAdapterorg.springframework.web.servlet.HandlerExceptionResolver=org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver,\org.springframework.web.servlet.mvc.annotation.ResponseStatusExceptionResolver,\org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolverorg.springframework.web.servlet.RequestToViewNameTranslator=org.springframework.web.servlet.view.DefaultRequestToViewNameTranslatororg.springframework.web.servlet.ViewResolver=org.springframework.web.servlet.view.InternalResourceViewResolverorg.springframework.web.servlet.FlashMapManager=org.springframework.web.servlet.support.SessionFlashMapManager
3.初始化 ThemeResolver:主要用来设置主题Theme
// 初始化 ThemeResolver:主要用来设置主题Theme
initThemeResolver(context);
/*** Initialize the ThemeResolver used by this class.* <p>If no bean is defined with the given name in the BeanFactory for this namespace,* we default to a FixedThemeResolver.*/private void initThemeResolver(ApplicationContext context) {try {this.themeResolver = context.getBean(THEME_RESOLVER_BEAN_NAME, ThemeResolver.class);if (logger.isTraceEnabled()) {logger.trace("Detected " + this.themeResolver);}else if (logger.isDebugEnabled()) {logger.debug("Detected " + this.themeResolver.getClass().getSimpleName());}}catch (NoSuchBeanDefinitionException ex) {// We need to use the default.// 从配置文件中获取默认的FixedThemeResolverthis.themeResolver = getDefaultStrategy(context, ThemeResolver.class);if (logger.isTraceEnabled()) {logger.trace("No ThemeResolver '" + THEME_RESOLVER_BEAN_NAME +"': using default [" + this.themeResolver.getClass().getSimpleName() + "]");}}}
4.初始化 HandlerMapping:映射器,用来将对应的request跟controller进行对应
// 初始化 HandlerMapping:映射器,用来将对应的request跟controller进行对应
initHandlerMappings(context);
/**初始化该类使用的HandlerMappings。<p>如果没有在BeanFactory中为这个命名空间定义HandlerMapping bean,我们默认为BeanNameUrlHandlerMapping。* Initialize the HandlerMappings used by this class.* <p>If no HandlerMapping beans are defined in the BeanFactory for this namespace,* we default to BeanNameUrlHandlerMapping.*/private void initHandlerMappings(ApplicationContext context) {// 将handlerMappings置空this.handlerMappings = null;// 如果开启探测功能,则扫描已注册的HandlerMapping的bean,添加到handlerMappings中if (this.detectAllHandlerMappings) {// Find all HandlerMappings in the ApplicationContext, including ancestor contexts.// 扫描已注册的handlerMapping的beanMap<String, HandlerMapping> matchingBeans =BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerMapping.class, true, false);// 添加到handlerMappings中,并进行排序if (!matchingBeans.isEmpty()) {this.handlerMappings = new ArrayList<>(matchingBeans.values());// We keep HandlerMappings in sorted order.AnnotationAwareOrderComparator.sort(this.handlerMappings);}}// 如果关闭探测功能,则获取Bean名称为handlerMapping对应的bean,将其添加到handlerMappingselse {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.// 如果未获得到,则获得默认配置的handlerMapping类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_test.properties");}}}
默认配置的handlerMapping
5.初始化 HandlerAdapter:处理适配器
初始化 HandlerAdapter:处理适配器,主要包含Http请求处理器适配器,简单控制器处理器适配器,注解方法处理器适配器
initHandlerAdapters(context);
/*** Initialize the HandlerAdapters used by this class.* <p>If no HandlerAdapter beans are defined in the BeanFactory for this namespace,* we default to SimpleControllerHandlerAdapter.*/private void initHandlerAdapters(ApplicationContext context) {this.handlerAdapters = null;if (this.detectAllHandlerAdapters) {// Find all HandlerAdapters in the ApplicationContext, including ancestor contexts.Map<String, HandlerAdapter> matchingBeans =BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerAdapter.class, true, false);if (!matchingBeans.isEmpty()) {this.handlerAdapters = new ArrayList<>(matchingBeans.values());// We keep HandlerAdapters in sorted order.AnnotationAwareOrderComparator.sort(this.handlerAdapters);}}else {try {HandlerAdapter ha = context.getBean(HANDLER_ADAPTER_BEAN_NAME, HandlerAdapter.class);this.handlerAdapters = Collections.singletonList(ha);}catch (NoSuchBeanDefinitionException ex) {// Ignore, we'll add a default HandlerAdapter later.}}// Ensure we have at least some HandlerAdapters, by registering// default HandlerAdapters if no other adapters are found.// 如果未获得到,则获得默认配置的HandlerAdapter类,HttpRequestHandlerAdapter,SimpleControllerHandlerAdapter,RequestMappingHandlerAdapterif (this.handlerAdapters == null) {this.handlerAdapters = getDefaultStrategies(context, HandlerAdapter.class);if (logger.isTraceEnabled()) {logger.trace("No HandlerAdapters declared for servlet '" + getServletName() +"': using default strategies from DispatcherServlet_test.properties");}}
默认配置的HandlerAdapter类,
6.初始化 HandlerExceptionResolver
初始化 HandlerExceptionResolver:基于HandlerExceptionResolver接口的异常处理
initHandlerExceptionResolvers(context);
/*** Initialize the HandlerExceptionResolver used by this class.* <p>If no bean is defined with the given name in the BeanFactory for this namespace,* we default to no exception resolver.*/private void initHandlerExceptionResolvers(ApplicationContext context) {// 置空 handlerExceptionResolver 处理this.handlerExceptionResolvers = null;// 自动扫描handlerExceptionResolver类型的beanif (this.detectAllHandlerExceptionResolvers) {// Find all HandlerExceptionResolvers in the ApplicationContext, including ancestor contexts.Map<String, HandlerExceptionResolver> matchingBeans = BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerExceptionResolver.class, true, false);if (!matchingBeans.isEmpty()) {this.handlerExceptionResolvers = new ArrayList<>(matchingBeans.values());// We keep HandlerExceptionResolvers in sorted order.AnnotationAwareOrderComparator.sort(this.handlerExceptionResolvers);}}// 获取名字为HANDLER_EXCEPTION_RESOLVER_BEAN_NAME的beanelse {try {HandlerExceptionResolver her =context.getBean(HANDLER_EXCEPTION_RESOLVER_BEAN_NAME, HandlerExceptionResolver.class);this.handlerExceptionResolvers = Collections.singletonList(her);}catch (NoSuchBeanDefinitionException ex) {// Ignore, no HandlerExceptionResolver is fine too.}}// Ensure we have at least some HandlerExceptionResolvers, by registering// default HandlerExceptionResolvers if no other resolvers are found.// 如果未获得到,则获取默认配置的handlerExceptionResolver类,ExceptionHandlerExceptionResolver,ResponseStatusExceptionResolver,DefaultHandlerExceptionResolverif (this.handlerExceptionResolvers == null) {this.handlerExceptionResolvers = getDefaultStrategies(context, HandlerExceptionResolver.class);if (logger.isTraceEnabled()) {logger.trace("No HandlerExceptionResolvers declared in servlet '" + getServletName() +"': using default strategies from DispatcherServlet_test.properties");}}}
7.初始化 RequestToViewNameTranslator
初始化 RequestToViewNameTranslator:当controller处理器方法没有返回一个View对象或逻辑视图名称,并且在该方法中没有直接往response的输出流里面写数据的时候,spring将会采用约定好的方式提供一个逻辑视图名称
initRequestToViewNameTranslator(context);
/*** Initialize the RequestToViewNameTranslator used by this servlet instance.* <p>If no implementation is configured then we default to DefaultRequestToViewNameTranslator.*/private void initRequestToViewNameTranslator(ApplicationContext context) {try {this.viewNameTranslator =context.getBean(REQUEST_TO_VIEW_NAME_TRANSLATOR_BEAN_NAME, RequestToViewNameTranslator.class);if (logger.isTraceEnabled()) {logger.trace("Detected " + this.viewNameTranslator.getClass().getSimpleName());}else if (logger.isDebugEnabled()) {logger.debug("Detected " + this.viewNameTranslator);}}catch (NoSuchBeanDefinitionException ex) {// We need to use the default.// 如果未找到,则获取默认的 RequestToViewNameTranslator 对象,DefaultRequestToViewNameTranslatorthis.viewNameTranslator = getDefaultStrategy(context, RequestToViewNameTranslator.class);if (logger.isTraceEnabled()) {logger.trace("No RequestToViewNameTranslator '" + REQUEST_TO_VIEW_NAME_TRANSLATOR_BEAN_NAME +"': using default [" + this.viewNameTranslator.getClass().getSimpleName() + "]");}}}
8.初始化 ViewResolver
初始化 ViewResolver: 将ModelAndView选择合适的视图进行渲染的处理器
initViewResolvers(context);
/*** Initialize the ViewResolvers used by this class.* <p>If no ViewResolver beans are defined in the BeanFactory for this* namespace, we default to InternalResourceViewResolver.*/private void initViewResolvers(ApplicationContext context) {// 置空 viewResolvers 处理this.viewResolvers = null;/// 自动扫描 ViewResolver 类型的 Beanif (this.detectAllViewResolvers) {// Find all ViewResolvers in the ApplicationContext, including ancestor contexts.Map<String, ViewResolver> matchingBeans =BeanFactoryUtils.beansOfTypeIncludingAncestors(context, ViewResolver.class, true, false);if (!matchingBeans.isEmpty()) {this.viewResolvers = new ArrayList<>(matchingBeans.values());// We keep ViewResolvers in sorted order.AnnotationAwareOrderComparator.sort(this.viewResolvers);}}// 获得名字为VIEW_RESOLVER_BEAN_NAME的beanelse {try {ViewResolver vr = context.getBean(VIEW_RESOLVER_BEAN_NAME, ViewResolver.class);this.viewResolvers = Collections.singletonList(vr);}catch (NoSuchBeanDefinitionException ex) {// Ignore, we'll add a default ViewResolver later.}}// Ensure we have at least one ViewResolver, by registering// a default ViewResolver if no other resolvers are found.// 如果未获得到,则获取默认配置的ViewResolver对象if (this.viewResolvers == null) {this.viewResolvers = getDefaultStrategies(context, ViewResolver.class);if (logger.isTraceEnabled()) {logger.trace("No ViewResolvers declared for servlet '" + getServletName() +"': using default strategies from DispatcherServlet_test.properties");}}}
9.初始化 FlashMapManager
初始化 FlashMapManager: 提供请求存储属性,可供其他请求使用
initFlashMapManager(context);
/*** Initialize the {@link FlashMapManager} used by this servlet instance.* <p>If no implementation is configured then we default to* {@code org.springframework.web.servlet.support.DefaultFlashMapManager}.*/private void initFlashMapManager(ApplicationContext context) {try {this.flashMapManager = context.getBean(FLASH_MAP_MANAGER_BEAN_NAME, FlashMapManager.class);if (logger.isTraceEnabled()) {logger.trace("Detected " + this.flashMapManager.getClass().getSimpleName());}else if (logger.isDebugEnabled()) {logger.debug("Detected " + this.flashMapManager);}}catch (NoSuchBeanDefinitionException ex) {// We need to use the default.// 未找到,则获取默认的 FlashMapManager 对象,SessionFlashMapManagerthis.flashMapManager = getDefaultStrategy(context, FlashMapManager.class);if (logger.isTraceEnabled()) {logger.trace("No FlashMapManager '" + FLASH_MAP_MANAGER_BEAN_NAME +"': using default [" + this.flashMapManager.getClass().getSimpleName() + "]");}}}
SpringMVC框架中Spring父容器和SpringMVC子容器加载的流程以及SpringMVC九大内置组件的初始已经完成接下来开始进行发送请求相关的源码。