spring容器启动

转载: https://blog.csdn.net/lieyanhaipo/article/details/58605545

一、Spring与WEB容器整合   

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

<!-- 配置Spring上下文监听器 -->  
<listener>  
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>  
</listener>  

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

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

<!-- 配置Spring配置文件路径 -->  
<context-param>  
    <param-name>contextConfigLocation</param-name>  
    <param-value>classpath*:applicationContext.xmlclasspath*:applicationContext-shiro.xml  
        </param-value>  
</context-param>

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


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

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());  
    }  
}  

2 ContextLoader类initWebApplicationContext()方法


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。

//servletContext表示的是一个web应用程序,每个web应用程序只有一个context,在servletContext中创建applicationContext

createWebApplicationContext()方法用来创建根上下文:

protected WebApplicationContext createWebApplicationContext(ServletContext sc) {  
    //从web.xml配置的contextClass参数中获取上下文类名,如果contextClass为空,则使用默认的。  
        //下文有说明  
    Class<?> contextClass = determineContextClass(sc);  
        //根上下文必须是ConfigurableWebApplicationContext的子类,否则抛出异常  
    if (!ConfigurableWebApplicationContext.class.isAssignableFrom(contextClass)) {  
        throw new ApplicationContextException("Custom context class [" + contextClass.getName() +  
                "] is not of type [" + ConfigurableWebApplicationContext.class.getName() + "]");  
    }  
    //BeanUtils.instantiateClass工具方法,根据类名创建类  
    return (ConfigurableWebApplicationContext) BeanUtils.instantiateClass(contextClass);  
}  

determineContextClass()方法返回根上下文的类名

static {  
    try {  
        //获取当前包下面的ContextLoader.properties文件,文件内容是:  
        //org.springframework.web.context.WebApplicationContext=org.springframework.web.context.
//support.XmlWebApplicationContext  
        ClassPathResource resource = new ClassPathResource(DEFAULT_STRATEGIES_PATH, ContextLoader.class);  
        defaultStrategies = PropertiesLoaderUtils.loadProperties(resource);  
    }  
    catch (IOException ex) {  
        throw new IllegalStateException("Could not load 'ContextLoader.properties': " + ex.getMessage());  
    }  
}  

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值