传统的SpringMVC项目中,需要在web.xml中配置ContextlistenerContextLoaderListener是负责引导启动和关闭Spring的Root上下文的监听器。主要将处理委托给ContextLoaderContextCleanupListener
类的继承关系。

ContextLoaderListener实现了ServletContextListener接口。该接口主要定义了两个行为:监听上下文创建(contextInitialized)和监听上下文销毁(contextDestroyed)。
ContextLoaderListener只是将方法的处理委托给ContextLoader

package org.springframework.web.context;import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;public class ContextLoaderListener extends ContextLoader implements ServletContextListener {public ContextLoaderListener() {}public ContextLoaderListener(WebApplicationContext context) {super(context);}//初始化Root WebApplication@Overridepublic void contextInitialized(ServletContextEvent event) {//委托给ContextLoaderinitWebApplicationContext(event.getServletContext());}//销毁Root WebApplication@Overridepublic void contextDestroyed(ServletContextEvent event) {   //委托给ContextLoadercloseWebApplicationContext(event.getServletContext());//委托给ContextCleanupListenerContextCleanupListener.cleanupAttributes(event.getServletContext());}}

ContextLoaderinitWebApplicationContext方法负责创建root web application context。

//初始化root web application context
public WebApplicationContext initWebApplicationContext(ServletContext servletContext) {//校验是否已经存在root application,if (servletContext.getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE) != null) {throw new IllegalStateException("Cannot initialize context because there is already a root application context present - " +"check whether you have multiple ContextLoader* definitions in your web.xml!");}Log logger = LogFactory.getLog(ContextLoader.class);servletContext.log("Initializing Spring root WebApplicationContext");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.//创建WebApplicationContext,并保存到变量中,等关闭时使用if (this.context == null) {this.context = createWebApplicationContext(servletContext);}//如果是ConfigurableWebApplicationContext,则配置上下文并刷新if (this.context instanceof ConfigurableWebApplicationContext) {ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext) this.context;if (!cwac.isActive()) {// The context has not yet been refreshed -> provide services such as// setting the parent context, setting the application context id, etcif (cwac.getParent() == null) {// The context instance was injected without an explicit parent ->// determine parent for root web application context, if any.ApplicationContext parent = loadParentContext(servletContext);cwac.setParent(parent);}configureAndRefreshWebApplicationContext(cwac, servletContext);}}//在ServletContext中设置属性,表明已经配置了root web application contextservletContext.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.isDebugEnabled()) {logger.debug("Published root WebApplicationContext as ServletContext attribute with name [" +WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE + "]");}if (logger.isInfoEnabled()) {long elapsedTime = System.currentTimeMillis() - startTime;logger.info("Root WebApplicationContext: initialization completed in " + elapsedTime + " ms");}return this.context;}catch (RuntimeException ex) {logger.error("Context initialization failed", ex);servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, ex);throw ex;}catch (Error err) {logger.error("Context initialization failed", err);servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, err);throw err;}}

该方法主要分为四步:

  1. 校验是否已经存在root WebApplicationContext
  2. 创建root WebApplicationContext
  3. 配置上下文并刷新
  4. 绑定root WebApplicationContext到servlet context上

这四步具体分析如下:

1.校验

校验的过程比较简单,主要是判断Servlet Context是否已经绑定过WebApplicationContext

2.创建对象

createWebApplicationContext()方法负责创建WebApplicationContext对象,主要过程是确定WebApplicationContext类,并实例化:

    protected WebApplicationContext createWebApplicationContext(ServletContext sc) {//查找WebApplicationContext的类Class<?> contextClass = determineContextClass(sc);if (!ConfigurableWebApplicationContext.class.isAssignableFrom(contextClass)) {throw new ApplicationContextException("Custom context class [" + contextClass.getName() +"] is not of type [" + ConfigurableWebApplicationContext.class.getName() + "]");}//实例化对象return(ConfigurableWebApplicationContext) BeanUtils.instantiateClass(contextClass);}

决定WebApplicationContext类的主要策略是先判断ServletContext是否配置了contextClass属性,如果是,则用该属性指定的类作为WebApplicationContext类,否则则是否默认策略。默认策略是根绝classpath下的ContextLoader.properties中配置的类作为WebApplicatioNCOntext类:

protected Class<?> determineContextClass(ServletContext servletContext) {//优先根据servletContext配置的contextClass属性String contextClassName = servletContext.getInitParameter(CONTEXT_CLASS_PARAM);if (contextClassName != null) {try {return ClassUtils.forName(contextClassName, ClassUtils.getDefaultClassLoader());}catch (ClassNotFoundException ex) {throw new ApplicationContextException("Failed to load custom context class [" + contextClassName + "]", ex);}}//在通过classpath下的`ContextLoader.properties`文件制定的类作为WebApplicationContext类//默认是XmlWebApplicationContextelse {contextClassName = defaultStrategies.getProperty(WebApplicationContext.class.getName());try {return ClassUtils.forName(contextClassName, ContextLoader.class.getClassLoader());}catch (ClassNotFoundException ex) {throw new ApplicationContextException("Failed to load default context class [" + contextClassName + "]", ex);}}}
配置与刷新

创建WebApplicationContext对象后,ContextLoader会判断是否是ConfigurableWebApplicationContext
ConfigurableWebApplicationContext拓展了WebApplicationContext的能力。其不仅扩展了自身方法,还继承了ConfigurableApplicationContext接口。

配置与刷新的步骤也正是利用了这些接口提供的能力。

    //配置并刷新上下文protected void configureAndRefreshWebApplicationContext(ConfigurableWebApplicationContext wac, ServletContext sc) {//设置IDif (ObjectUtils.identityToString(wac).equals(wac.getId())) {// The application context id is still set to its original default value// -> assign a more useful id based on available informationString idParam = sc.getInitParameter(CONTEXT_ID_PARAM);if (idParam != null) {wac.setId(idParam);}else {// Generate default id...wac.setId(ConfigurableWebApplicationContext.APPLICATION_CONTEXT_ID_PREFIX +ObjectUtils.getDisplayString(sc.getContextPath()));}}//WebApplicationContext绑定Servlet Contextwac.setServletContext(sc);String configLocationParam = sc.getInitParameter(CONFIG_LOCATION_PARAM);if (configLocationParam != null) {wac.setConfigLocation(configLocationParam);}// The wac environment's #initPropertySources will be called in any case when the context// is refreshed; do it eagerly here to ensure servlet property sources are in place for// use in any post-processing or initialization that occurs below prior to #refreshConfigurableEnvironment env = wac.getEnvironment();if (env instanceof ConfigurableWebEnvironment) {((ConfigurableWebEnvironment) env).initPropertySources(sc, null);}//自定义上下文初始过程,留给用户的拓展机制customizeContext(sc, wac);//刷新上下文,加载beanwac.refresh();}

创建流程图如下:

转载于:https://www.cnblogs.com/insaneXs/p/11115862.html

SpringMVC Root WebApplicationContext启动流程相关推荐

  1. tomcat启动停在Initializing Spring root WebApplicationContext

    tomcat启动停在Initializing Spring root WebApplicationContext 解决方法:检查数据库连接IP是否能连通 posted on 2015-11-23 14 ...

  2. tomcat 启动时 Initializing Spring root WebApplicationContext停止启动

    SSH 框架整合.tomcat 容器初次启动可以正常加载spring信息,以后在重新启动容器就会卡在 Initializing Spring root WebApplicationContext 停止 ...

  3. tomcat启动停止在 Initializing Spring root WebApplicationContext,就不运行了

    启动项目的时候,项目一直运行到 Initializing Spring root WebApplicationContext,就停止不运行了,也不报错,开始真的很苦恼,后来把log日志的模式改为 de ...

  4. SpringMVC的启动流程与原理

    做过web项目的都知道页面连接后端程序中间是需要一个连接器来进行连接控制的.拿最常用的web容器tomcat来说,我们用tomcat搭建一个简单的web应用,就是配置好tomcat的web.xml文件 ...

  5. 详述 Spring MVC 启动流程及相关源码分析

    文章目录 Web 应用部署初始化过程(Web Application Deployement) Spring MVC 启动过程 Listener 的初始化过程 Filter 的初始化 Servlet ...

  6. SPRINGBOOT启动流程及其原理

    Spring Boot.Spring MVC 和 Spring 有什么区别? 分别描述各自的特征: Spring 框架就像一个家族,有众多衍生产品例如 boot.security.jpa等等:但他们的 ...

  7. 关于Spring体系的各种启动流程

    在介绍spring的启动之前,先来说下启动过程中使用到的几个类 基本组件 1.BeanFactory:spring底层容器,定义了最基本的容器功能,注意区分FactoryBean 2.Applicat ...

  8. SSM项目的启动流程深入解析

    1 环境说明 本文的内容基于Tomcat9.0.10.Spring 4.3 2 Tomcat加载应用的顺序 在我们正式介绍SSM项目是怎么启动之前,我们要先来简单介绍一下Tomcat.很多人在介绍To ...

  9. Initializing Spring root WebApplicationContext

    Spring +SpringMVC+MyBatis 启动项目到 Initializing Spring root WebApplicationContext  不执行了 我的问题原因是  <se ...

最新文章

  1. Java项目:资源下载工具(java+swing)
  2. SAP MM 移动类型343不开放给业务人员之思考
  3. document.getElementById()和document.forms[0].submit()
  4. Linux-NFS——配置过程
  5. IE6,7下实现white-space:pre-wrap;
  6. Linux虚拟机-配置文件说明
  7. 1.Python介绍
  8. python爬虫审查元素_python爬虫3——获取审查元素(板野友美吧图片下载)
  9. WinForm软件开机自动启动详细方法
  10. JavaMaven【三、常用指令】
  11. mysql java 日期_Mysql和JAVA中的几个日期操作
  12. 【098】在线Cron表达式生成器-在线生成Cron,格式化Xml
  13. crack-jar游戏之乐游
  14. mysql数据库的连接
  15. 阿狸(Hans设计卡通形象)的幸福生活 ---- 充满趣味性(可自定义更改)
  16. MII接口(Media Independent Interface)
  17. 2018最新苹果公司开发者账号设置税务
  18. html 淡出淡入轮播图,用CSS3 transition属性实现淡入淡出轮播图
  19. MATLAB 面向对象编程(十二)抽象类
  20. matlab 水波模拟 代码,matlab - 在Matlab中模拟一艘在水波中航行的船 - SO中文参考 - www.soinside.com...

热门文章

  1. asp.net 调用本地php,.NET_Asp.net获取服务器指定文件夹目录文件并提供下载的方法,本文实例讲述了Asp.net获取服务 - phpStudy...
  2. jfinal连接mysql数据库_JFinal中怎么获得当前数据库连接的数据库类型?
  3. c语言中合法转义字符,判断c语言合法转义字符
  4. 百度之星2019 初赛一 题解
  5. Java 集合系列(一)
  6. F. 更改apache端口号
  7. tomcat,很多时候,可以在服务server.xml中可以实现一些效果
  8. Arduino MEGA 2560找不到驱动怎么办
  9. Laravel生命周期
  10. JS判断请求来自Android手机还是iPhone手机,根据不同的手机跳转到不同的链接。...