servlrt程序的入口点是_spring启动入口

一、Spring与WEB容器整合

web项目中,Spring启动是在web.xml配置监听器,如下所示:

Xml代码

org.springframework.web.context.ContextLoaderListener

可以看看ContextLoaderListener类,它实现了Tomcat容器的ServletContextListener接口,所以它与普通的Servlet监听是一样的。同样是重写到两个方法:contextInitialized()方法在web容器初始化时执行,contextDestroyed()方法在容器销毁时执行。

WEB容器启动时会触发初始化事件,ContextLoaderListener监听到这个事件,其contextInitialized()方法会被调用,在这个方法中Spring会初始化一个根上下文,即WebApplicationContext。这是一个接口,其实际默认实现类是XmlWebApplicationContext。这个就是Spring IOC的容器,其对应bean定义的配置信息由web.xml中的context-param来指定

Xml代码

contextConfigLocation

classpath*:applicationContext.xmlclasspath*:applicationContext-shiro.xml

在Spring IOC 容器启动初始化完毕之后,会将其储存到ServletContext中。形式如下:servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, WebApplicationContext context);

注:以前我们写Servlet程序的时候,如果在Tomcat容器启动的时候需要绑定一些参数或者做一些全局处理,那么就需要实现ServletContextListener接口,在contextInitialized方法中编写必要的代码。然后在web.xml添加配置listener

在ContextLoaderListener类中,只是实现了ServletContextListener提供的到两个方法,Spring启动主要的逻辑在父类ContextLoader的方法initWebApplicationContext实现。ContextLoaderListener的作用就是启动web容器时自动装配ApplicationContext的配置信息。更细化一点讲,Spring的启动过程其实就是Spring IOC容器的启动过程。

Java代码

public class ContextLoaderListener extends ContextLoader implements ServletContextListener {

/**

* Initialize the root web application context.

*/

@Override

public void contextInitialized(ServletContextEvent event) {

initWebApplicationContext(event.getServletContext());

}

/**

* Close the root web application context.

*/

@Override

public void contextDestroyed(ServletContextEvent event) {

closeWebApplicationContext(event.getServletContext());

ContextCleanupListener.cleanupAttributes(event.getServletContext());

}

}

二、ContextLoader剖析

从上一部分ContextLoaderListener类可以得知,ContextLoader实际执行Spring容器的初始化,Spring整个的配置工作都是在ContextLoader完成的,这里参数ServletContextEvent由web容器提供,不做说明。ContextLoaderListener很好理解,所以我们主要看ContextLoader类。用Maven引入Spring的源码,打开ContextLoader类,类注释的第一行就是

Xml代码

/**

* Performs the actual initialization work for the root application context.

......

**/

用google翻译:实际执行根应用上下文的初始化工作。这里的根应用上下文就是上文所写的WebApplicationContext。我们先看看ContextLoader的时序图

ContextLoader类initWebApplicationContext()方法

Java代码

/**

* 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) {

//判断ServletContext是否已经存在WebApplication,如果存在则抛出异常

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) {

//创建WebApplicationContext(下文有说明)

this.context = createWebApplicationContext(servletContext);

}

if (this.context instanceof ConfigurableWebApplicationContext) {

ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext) this.context;

if (!cwac.isActive()) {

// The context has not yet been refreshed -> provide services such as

// setting the parent context, setting the application context id, etc

if (cwac.getParent() == null) {

// 得到根上下文的父上下文,然后设置到根上下文 。一般的web项目parent为空

ApplicationContext parent = loadParentContext(servletContext);

cwac.setParent(parent);

}

//从web.xml加载参数,初始化跟上下文WebApplicationContext,创建bean工厂和bean对象。

//这个过程比较麻烦,下一篇文章专门分析

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;

}

}

在这个方法中ServletContext是由web容器监听器(ContextLoaderListener)提供。首先判断servlectContext中是否已经存在根上下文,如果存在,则抛出异常;否则通过createWebApplicationContext方法创建新的根上下文。然后通过loadParentContext()方法为其设置父上下文。再通过configureAndRefreshWebApplicationContext为根上下文构建bean工厂和bean对象。 最后把上下文存入servletContext,并且存入currentContextPerThread。至此初始化过程完毕,接下来可以获取WebApplicationContext,进而用getBean("bean name")得到bean。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值