Spring 源碼學習(二) IOC容器啓動過程

這一節主要是記錄一下Spring Ioc 容器的啓動過程。java

 Spring 的 Ioc 容器是怎麼被加載和使用的? web容器爲它提供了宿主環境 ServlectContext,  Tomcat 啓動時會讀取web.xml。web

 而且實例化web.xml中配置的ContextLoaderListener ,下面看一下ContextLoaderListener的建立過程:spring

 在實例化ContextLoaderListener 以後,經過接口回調執行ContextLoaderListener 類中的contextInitialized(ServletContextEvent event)方法,該方法的做用是初始化根上下文app

  (注:WebApplicationContext 是ApplicationContext 的拓展接口,而Spring默認提供的根上下文是XmlWebApplicationContext。)ide


代碼:post

public WebApplicationContext initWebApplicationContext(ServletContext servletContext) { 

//若servletContext中存在WebApplicationContext 則拋出異常 

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!");

} 

//…………省略 
//初始化
WebApplicationContext 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) {
//建立webApplication的實例 
this.context =createWebApplicationContext(servletContext); 
}
 //省略代碼在下面給出
}

 

createWebApplicationContext(servletContext) 方法的做用是建立根上下WebApplicationContext的實例this

代碼:spa

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

  }


這裏determineContextClass(ServletContext sc)  用於返回ApplicationContext的實現類,若是沒有在配置文件中配置自定義的ApplicationContext,默認返回 XmlWebApplicationContext ,獲得實例後對其進行檢查,知足條件則返回它的實例。日誌

createWebApplicationContext方法下面省略的代碼:code

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

     

這一步是判斷返回的根上下文實例context有沒有父上下文,取決於在web.xml中定義的參數:locatorFactorySelector,這是一個可選參數,加載完父上下文以後,執行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
            // -> assign a more useful id based on available information
           //………省略
        }
        wac.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 conte        //xt
        // 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 #refresh
        //………省略
        wac.refresh();
  }

 

  上面的方法setServletContext  爲根上下文設置ServletContext的引用 , 執行根上下文的refresh()方法, 就是上一節說的,建立BeanFacotry的過程,執行完這方法在啓動日誌就能夠看到

信息: Loading XML bean definitions from class path resource [spring.xml]


   這個時候就完成了對spring.xml資源的讀取,到此就結束了根上下文(Application)的配置與加載資源,servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, this.context)這句代碼就是把上下文存入ServletContext當中,下次獲取根上下文的時候就能夠經過 WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE屬性獲取。


到此ContextLoaderListener的建立就結束了。

相關文章
相關標籤/搜索