SpringMVC源码-SpringMVC框架中Spring父容器和SpringMVC子容器加载的流程以及SpringMVC九大内置组件的初始

一、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类图:
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九大内置组件的初始已经完成接下来开始进行发送请求相关的源码。

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/437578.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

机器学习西瓜书笔记(十三) 第十三章半监督学习+代码

第十三章 13 半监督学习13.1 未标记样本13.3.1 小结 13.2 生成式方法13.2.1 小结 13.3 半监督SVM13.3.1 小结 13.4 图半监督学习13.4.1 小结 13.5 基于分歧的方法13.5.1 小结 13.6 半监督聚类13.6.1 小结 13.7 代码&#xff1a;手写数据集上的标签传播-性能展示章末小结 13 半监…

数据结构——初识树和二叉树

线性结构是一对一的关系&#xff0c;意思就是只有唯一的前驱和唯一的后继&#xff1b; 非线性结构&#xff0c;如树形结构&#xff0c;它可以有多个后继&#xff0c;但只有一个前驱&#xff1b;图形结构&#xff0c;它可以有多个前驱&#xff0c;也可以有多个后继。 树的定义…

变电站红外检测数据集 1180张 变电站红外 标注voc yolo 13类

变电站红外检测数据集 1180张 变电站红外 标注voc yolo 13类 变电站红外检测数据集 名称 变电站红外检测数据集 (Substation Infrared Detection Dataset) 规模 图像数量&#xff1a;1185张图像。类别&#xff1a;13种设备类型。标注个数&#xff1a;2813个标注。 数据划分…

多模态RAG实现

在标准 RAG 中&#xff0c;输入文档包含文本数据。LLM 利用上下文学习&#xff0c;通过检索与所提查询上下文相匹配的文本文档块来提供更相关、更准确的答案。 但是&#xff0c;如果文档包含图像、表格、图表等以及文本数据&#xff0c;该怎么办&#xff1f; 不同的文档格式包…

华为GaussDB数据库之Yukon安装与使用

一、Yukon简介 Yukon&#xff08;禹贡&#xff09;&#xff0c;基于openGauss、PostgreSQL、GaussDB数据库扩展地理空间数据的存储和管理能力&#xff0c;提供专业的GIS&#xff08;Geographic Information System&#xff09;功能&#xff0c;赋能传统关系型数据库。 Yukon 支…

linux桌面软件(wps)内嵌到其他窗口

程序测试环境是&#xff1a;slackware系统&#xff0c;属于linux系统&#xff0c;有桌面&#xff08;Xface Session&#xff09;。系统镜像是&#xff1a;slackware64-15.0-install-dvd.iso。qt、c代码实现。 程序功能&#xff1a;将已经打开的wps&#xff08;word、pdf等都可…

Android SystemUI组件(09)唤醒亮屏 锁屏处理流程

该系列文章总纲链接&#xff1a;专题分纲目录 Android SystemUI组件 本章关键点总结 & 说明&#xff1a; 说明&#xff1a;本章节持续迭代之前章节的思维导图&#xff0c;主要关注左侧上方锁屏分析部分 唤醒亮屏 即可。 Power按键的处理逻辑最终是由PhoneWindowManager来…

Watchdog Timers(WDT)

文章目录 1. 介绍2. Feature List3. 概述3.1. Safety Watchdog3.2. CPU Watchdog 4. 看门狗定时器功能5. Endinit Functions5.1 Password Access to WDTxCON05.1.1 Static Password5.1.2 Automatic Password Sequencing 5.2 Check Access to WDTxCON05.3 Modify Access to WDTx…

[C++]使用C++部署yolov11目标检测的tensorrt模型支持图片视频推理windows测试通过

官方框架&#xff1a; https://github.com/ultralytics/ultralytics yolov8官方最近推出yolov11框架&#xff0c;标志着目标检测又多了一个检测利器&#xff0c;于是尝试在windows下部署yolov11的tensorrt模型&#xff0c;并最终成功。 重要说明&#xff1a;安装环境视为最基…

Tiny-universe手戳大模型TinyRAG--task4

TinyRAG 这个模型是基于RAG的一个简化版本&#xff0c;我们称之为Tiny-RAG。Tiny-RAG是一个基于RAG的简化版本&#xff0c;它只包含了RAG的核心功能&#xff0c;即Retrieval和Generation。Tiny-RAG的目的是为了帮助大家更好的理解RAG模型的原理和实现。 1. RAG 介绍 LLM会产…

Halcon基础系列1-基础算子

1 窗口介绍 打开Halcon 的主界面主要有图形窗口、算子窗口、变量窗口和程序窗口&#xff0c;可拖动调整位置&#xff0c;关闭后可在窗口下拉选项中找到。 2 显示操作 关闭-dev_close_window() 打开-dev_open_window (0, 0, 712, 512, black, WindowHandle) 显示-dev_display(…

超级干货:Air780E之RS485通信篇,你学会了吗?

今天&#xff0c;我们来学习低功耗4G模组Air780E的RS485通信&#xff0c;同学们&#xff0c;你学习了吗&#xff1f; 一、RS485简介 物联网&#xff08;IoT&#xff09;在工业场景中的应用越来越广泛&#xff0c;而RS485是一种常见的通信协议&#xff0c;广泛应用于工业自动…

快手:数据库升级实践,实现PB级数据的高效管理|OceanBase案例

本文作者&#xff1a;胡玉龙&#xff0c;快手技术专家 快手在较初期采用了OceanBase 3.1版本成功替换了多个核心业务、数百套的MySQL集群。至2023年&#xff0c;快手的数据量已突破800TB大关&#xff0c;其中最大集群的数据量更是达到了数百TB级别。为此&#xff0c;快手将数据…

关于视频监控介入的部分内容,使用的是海康H5web播放的模式

这是原发直接能在系统中使用。里面的样式自己修改&#xff0c;主要是在引入时出现黑色的框就是引入成功&#xff0c;需要在public文件夹中引入h5player.min.js文件就可以。 <template><div class"Shiping"><el-container><el-header><di…

【数据分享】2001-2023年我国省市县镇四级的逐月平均气温数据(免费获取/Shp/Excel格式)

之前我们分享过1901-2023年1km分辨率逐月平均气温栅格数据&#xff0c;该数据来源于国家青藏高原科学数据中心。为方便大家使用&#xff0c;我们还基于上述平均气温栅格数据将数据处理为Shp和Excel格式的省市县三级逐月平均气温数据&#xff08;可查看之前的文章获悉详情&#…

ubuntu 18.04 cuda 11.01 gpgpu-sim 裸机编译

1&#xff0c;环境 ubuntu 18.04 x86_64 cuda 11.01 gpgpu-sim master commit 90ec3399763d7c8512cfe7dc193473086c38ca38 2&#xff0c;预备环境 一个比较新的 ubuntu 18.04&#xff0c;为了迎合 cuda 11.01 的版本需求 安装如下软件&#xff1a; sudo apt-get instal…

【Linux】几种常见配置文件介绍

配置文件目录 linux 系统中有很多配置文件目录 /etc/systemd/system /lib/systemd/system /usr/lib/systemd/system 【结果就是这个目录配置文件是源头】 这三者有什么样的关系呢&#xff1f; 以下是网络上找的资料汇总&#xff0c;并加了一些操作验证。方便后期使用 介…

VMware中Ubuntu系统Docker正常运行但网络不通(已解决)

问题描述&#xff1a;在VMware中的Ubuntu系统下部署了Docker&#xff0c;当在docker容器中运行Eureka微服务时&#xff0c;发现Eureka启动正常&#xff0c;但无法通过网页访问该容器中Eureka。 解决办法如下&#xff1a; 1、创建桥接网络&#xff1a;test-net sudo docker n…

ARM 架构、cpu

一、ARM的架构 ARM是一种基于精简指令集&#xff08;RISC&#xff09;的处理器架构. 1、ARM芯片特点 ARM芯片的主要特点有以下几点&#xff1a; 精简指令集&#xff1a;ARM芯片使用精简指令集&#xff0c;即每条指令只完成一项简单的操作&#xff0c;从而提高指令的执行效率…

进程的创建、多任务及退出

一、创建进程 1、并发与并行 为了提高计算机执行任务的效率&#xff0c;一般采用的解决方案就是能够让多个任务同时进行&#xff0c;可以使用 并发 与 并行两种方式 并行 : 在 cpu 多核的支持下&#xff0c;实现物理上的同时执行 并发 : 在有限的 cpu 核芯的情况下 , …