在项目的web.xml中配置

 <listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>

此配置为spring容器加载入口,因为其javax.servlet.ServletContextListener接口。

下面代码为ServletContextListener的源码:

public interface ServletContextListener extends EventListener {
/**
** Notification that the web application initialization
** process is starting.
** All ServletContextListeners are notified of context
** initialization before any filter or servlet in the web
** application is initialized.
*/
 
public void contextInitialized ( ServletContextEvent sce ); /**
** Notification that the servlet context is about to be shut down.
** All servlets and filters have been destroy()ed before any
** ServletContextListeners are notified of context
** destruction.
*/
public void contextDestroyed ( ServletContextEvent sce );
}

其中contextInitialized方法为web应用加载入口,实现此方法即可在其中加载自定义初始化web应用。

回过头看ContextLoaderListener中的初始化工作:

 /**
* Initialize the root web application context.
*/
public void contextInitialized(ServletContextEvent event) {
this.contextLoader = createContextLoader();
if (this.contextLoader == null) {
this.contextLoader = this;
}
this.contextLoader.initWebApplicationContext(event.getServletContext());
}

其具体初始化工作在其父类org.springframework.web.context.ContextLoader中的initWebApplicationContext方法中进行:

/**
* Initialize Spring's web application context for the given servlet context,
* using the application context provided at construction time, or creating a new one
* according to the "{@link #CONTEXT_CLASS_PARAM contextClass}" and
* "{@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) {
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.
if (this.context == null) {
this.context = createWebApplicationContext(servletContext);
}
if (this.context instanceof ConfigurableWebApplicationContext) {
ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext) this.context;
if (!cwac.isActive()) {
// The context has not yet been refreshed -> provide services such as
// setting the parent context, setting the application context id, etc
if (cwac.getParent() == null) {
// The context instance was injected without an explicit parent ->
// determine parent for root web application context, if any.
ApplicationContext parent = loadParentContext(servletContext);
cwac.setParent(parent);
}
configureAndRefreshWebApplicationContext(cwac, servletContext);
}
}
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.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)方法determineContextClass其返回一个WebApplicationContext的实现类,要么是默认的XmlWebApplicationContext,要么是一个指定的自定义的类。

先看方法源码:

 /**
* Return the WebApplicationContext implementation class to use, either the
* default XmlWebApplicationContext or a custom context class if specified.
* @param servletContext current servlet context
* @return the WebApplicationContext implementation class to use
* @see #CONTEXT_CLASS_PARAM
* @see org.springframework.web.context.support.XmlWebApplicationContext
*/
protected Class<?> determineContextClass(ServletContext servletContext) {
String contextClassName = servletContext.getInitParameter(CONTEXT_CLASS_PARAM);
if (contextClassName != null) {
try {
return ClassUtils.forName(contextClassName, ClassUtils.getDefaultClassLoader());
}
catch (ClassNotFoundException ex) {
throw new ApplicationContextException(
"Failed to load custom context class [" + contextClassName + "]", ex);
}
}
else {
contextClassName = defaultStrategies.getProperty(WebApplicationContext.class.getName());
try {
return ClassUtils.forName(contextClassName, ContextLoader.class.getClassLoader());
}
catch (ClassNotFoundException ex) {
throw new ApplicationContextException(
"Failed to load default context class [" + contextClassName + "]", ex);
}
}
}

先查看是否有用户自定义的context类,其配置方式是在web.xml中配置初始化属性其name为contextClass,原因是:

    /**
* Config param for the root WebApplicationContext implementation class to use: {@value}
* @see #determineContextClass(ServletContext)
* @see #createWebApplicationContext(ServletContext, ApplicationContext)
*/
public static final String CONTEXT_CLASS_PARAM = "contextClass";

在web.xml中的配置例如:

<context-param>
<param-name>contextClass</param-name>
<param-value>xxxxxxxxxx</param-value>
</context-param>

如果没有自定义配置的话,实现加载其默认WebApplicationContext实现类org.springframework.web.context.support.XmlWebApplicationContext。

2)方法createWebApplicationContext将determineContextClass方法返回的Class类实例化。并将其实例类向上转型为ConfigurableWebApplicationContext类型。

默认的返回应该是ConfigurableWebApplicationContext的子类org.springframework.web.context.support.XmlWebApplicationContext实例。

下面是方法的源码:

 /**
* Instantiate the root WebApplicationContext for this loader, either the
* default context class or a custom context class if specified.
* <p>This implementation expects custom contexts to implement the
* {@link ConfigurableWebApplicationContext} interface.
* Can be overridden in subclasses.
* <p>In addition, {@link #customizeContext} gets called prior to refreshing the
* context, allowing subclasses to perform custom modifications to the context.
* @param sc current servlet context
* @return the root WebApplicationContext
* @see ConfigurableWebApplicationContext
*/
protected WebApplicationContext createWebApplicationContext(ServletContext sc) {
Class<?> contextClass = determineContextClass(sc);
if (!ConfigurableWebApplicationContext.class.isAssignableFrom(contextClass)) {
throw new ApplicationContextException("Custom context class [" + contextClass.getName() +
"] is not of type [" + ConfigurableWebApplicationContext.class.getName() + "]");
}
return (ConfigurableWebApplicationContext) BeanUtils.instantiateClass(contextClass);
}

3)方法configureAndRefreshWebApplicationContext配置web应用

源码为:

 protected void configureAndRefreshWebApplicationContext(ConfigurableWebApplicationContext wac, ServletContext sc) {
if (ObjectUtils.identityToString(wac).equals(wac.getId())) {
// The application context id is still set to its original default value
// -> assign a more useful id based on available information
String idParam = sc.getInitParameter(CONTEXT_ID_PARAM);
if (idParam != null) {
wac.setId(idParam);
}
else {
// Generate default id...
if (sc.getMajorVersion() == 2 && sc.getMinorVersion() < 5) {
// Servlet <= 2.4: resort to name specified in web.xml, if any.
wac.setId(ConfigurableWebApplicationContext.APPLICATION_CONTEXT_ID_PREFIX +
ObjectUtils.getDisplayString(sc.getServletContextName()));
}
else {
wac.setId(ConfigurableWebApplicationContext.APPLICATION_CONTEXT_ID_PREFIX +
ObjectUtils.getDisplayString(sc.getContextPath()));
}
}
} wac.setServletContext(sc);
String initParameter = sc.getInitParameter(CONFIG_LOCATION_PARAM);
if (initParameter != null) {
wac.setConfigLocation(initParameter);
}
customizeContext(sc, wac);
wac.refresh();
}

其中String initParameter = sc.getInitParameter(CONFIG_LOCATION_PARAM);获取在web.xml中配置的contextConfigLocation参数来确定spring配置文件的位置。

其中的ConfigurableWebApplicationContext类型参数实际上是其子类org.springframework.web.context.support.XmlWebApplicationContext的类型参数,

其中方法customizeContext是定制化conext的方法,如果没有在web.xml中配置contextInitializerClasses初始化参数则此方法不做任何工作。

其中wac.refresh();方法其是在org.springframework.web.context.support.XmlWebApplicationContext的父类org.springframework.context.support.AbstractApplicationContext中实现。它才开始真正的spring配置工作。

spring容器启动原理分析1的更多相关文章

  1. Spring Boot 启动原理分析

    https://yq.aliyun.com/articles/6056 转 在spring boot里,很吸引人的一个特性是可以直接把应用打包成为一个jar/war,然后这个jar/war是可以直接启 ...

  2. spring boot启动原理步骤分析

    spring boot最重要的三个文件:1.启动类 2.pom.xml 3.application.yml配置文件 一.启动类->main方法 spring boot启动原理步骤分析 1.spr ...

  3. 从头看看Tomcat启动Spring容器的原理

    通过带注解Spring Boot可以启动一个web容器,并初始化bean容器.那么Tomcat启动并初始化spring容器的原理是怎样的? Tomcat启动web程序时会创建一对父子容器(图1): 有 ...

  4. Spring5深度源码分析(三)之AnnotationConfigApplicationContext启动原理分析

    代码地址:https://github.com/showkawa/spring-annotation/tree/master/src/main/java/com/brian AnnotationCon ...

  5. Spring Boot -- 启动流程分析之ApplicationContext 中

    上一节我们已经分析到AbsractApplicationContext类refresh方法中的postProcessBeanFactory方法,在分析registerBeanPostProcessor ...

  6. SpringBoot启动原理分析

    用了差不多两年的SpringBoot了,可以说对SpringBoot已经很熟了,但是仔细一想SpringBoot的启动流程,还是让自己有点懵逼,不得不说是自己工作和学习的失误,所以以此文对Spring ...

  7. Spring依赖注入原理分析

    在分析原理之前我们先回顾下依赖注入的概念: 我们常提起的依赖注入(Dependency Injection)和控制反转(Inversion of Control)是同一个概念.具体含义是:当某个角色( ...

  8. Spring Boot启动原理解析

    Spring Boot启动原理解析http://www.cnblogs.com/moonandstar08/p/6550758.html 前言 前面几章我们见识了SpringBoot为我们做的自动配置 ...

  9. spring容器IOC原理解析

    原理简单介绍: Spring容器的原理,其实就是通过解析xml文件,或取到用户配置的bean,然后通过反射将这些bean挨个放到集合中,然后对外提供一个getBean()方法,以便我们获得这些bean ...

随机推荐

  1. 结对作业--基于GUI的四则运算生成器

    组员:201421123015 陈麟凤 201421123019 张志杰 201421123020 黄海鸿 coding 地址 :https://coding.net/u/zhang1995/p/wo ...

  2. 第二次项目冲刺(Beta阶段)--第七天

    一.站立式会议照片 二.项目燃尽图 三.项目进展 codingnet:https://git.coding.net/tuoxie/chachong-beta.git 1.对项目进行全面的测试 2.继续 ...

  3. Struts2配置文件复用代码【web.xml、struts.xml、常量配置】

    web.xml的分发器代码: <!-- 引入struts核心过滤器 --> <filter> <filter-name>struts2</filter-nam ...

  4. OJ周末题

    字符串分割 字符统计 记票统计

  5. Spring - BeanPostProcessor接口(后处理器)讲解

    概述: BeanPostProcessor接口是众多Spring提供给开发者的bean生命周期内自定义逻辑拓展接口中的一个,其他还有类似InitializingBean,DisposableBean, ...

  6. Java报文或者同步的数据有个别乱码情况的处理.

    从其它系统获取到的用户数据,1万多条数据有其中有2条数据是乱码形式,这种形式表现为最后一个字符和本身的分隔符组成了一个乱码   错误数据 :  220296|+|黄燕 鄚+|7|+|7|+|02220 ...

  7. Oracle存储过程经典入门

    ok基本就这些介绍

  8. Promise小书(长文)

    promise基础 Promise是异步编程的一种解决方案.ES6 Promise的规范来源于Promises/A+社区,它有很多版本的实现. Promise比传统的解决方案(回调函数和事件)更合理和 ...

  9. 非position:fixed,footer自動調到屏幕底部

    一.980px手機端寫法: $(function(){        var sh=$('section').height();     var ww=$(window).width();       ...

  10. 保存数据到sdcard中去

    这里只贴上核心的代码:其它自行脑补!