ContextLoaderListener加載過程


在web.xml中,配置ContextLoaderListener

 <!-- 配置Listener,用來創建Spring容器 -->
  <listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
  </listener>

  <context-param>
  	<!-- 配置Listener參數:告訴它Spring的配置文件位置,它好去創建容器 -->
    <param-name>contextConfigLocation</param-name>
    <param-value>classpath:application-context*.xml</param-value>
  </context-param>

 

說明:<listener>標簽中,ContextLoaderListener用來創建Spring容器;而<context-param>標簽,用來指定了spring配置文件的位置,該兩個標簽共同起作用,也就可以在web項目啟動后,成功的創建了Spring容器了。 

 

分析如下:

1.ContextLoaderListener實現了ServletContextListener接口,ServletContextListener是Java EE標准接口之一,類似tomcat,jetty的java容器啟動時便會觸發該接口的contextInitialized。也就是說會激活調用ContextLoaderListener的contextInitialized()方法

2.ContextLoaderListener類中的contextInitialized方法如下

	/**
	 * Initialize the root web application context.
	 */
	@Override
	public void contextInitialized(ServletContextEvent event) {
		initWebApplicationContext(event.getServletContext());
	}

  

3.我們在進入到ClassLoader類的initWebApplicationContext( )方法內部,會注入ServletContext   servletContext的參數對象,同時幫我們返回一個WebApplicationContext容器對象,代碼如下:

  

public WebApplicationContext initWebApplicationContext(ServletContext servletContext) {
		
	/** 此處省略部分代碼 */

	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 {
		
		if (this.context == null) {
			/**
			* 重要,該方法會幫我們創建WebApplicationConntext,並賦值給ContextLoaderListener類的context對象。
			* 說明:ContextLoaderListener類的context屬性來自於它的父類
			*/
			this.context = createWebApplicationContext(servletContext);
		}
		if (this.context instanceof ConfigurableWebApplicationContext) {
			ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext) this.context;
			if (!cwac.isActive()) {

				/** 此處省略部分代碼 */
				
				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;
		}
		
		/** 此處省略部分代碼 */

		return this.context;
	}
		
}

 

  debug打斷點我們可以看到注入ServletContext   servletContext的參數對象ApplicationContextFacade類型的對象,內部是通過Map來實現的,用來加載Spring的配置文件。

  也就是說該方法執行完后,我們就會拿到WebApplicationContext類型的Spring容器對象。那么該方法內部具體是如何加載Spring配置文件的呢,是如何創建WebApplicationContext對象?我們接着往下看

 

  4.我們可以看到該行代碼:this.context = createWebApplicationContext(servletContext);  該方法用於創建WebApplicationContext對象,並賦值給context屬性。WebApplicationContext是一個接口類,本質上返回的是XmlWebApplicationContext,它就是Spring容器了

 

  5.我們再進入到createWebApplicationContext(servletContext)方法中:

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

  會將剛才注入的ApplicationContextFacade對象傳入,用於指定Spring的配置文件位置,它的內部是通過Map來實現的,也就是說,該類會解析<context-param>標簽的內容,加載Spring配置文件,有了配置文件就可以初始化容器了

  

  6.createWebApplicationContext( ) 調用determineContextClass( )方法

     determineContextClass有如下代碼:

  contextClassName = defaultStrategies.getProperty(WebApplicationContext.class.getName());

 

 7.很明顯是從defaultStrategies中加載的

  ContextLoader 類中有段靜態代碼:會加載默認配置,也就是會加載<param-value>classpath:application-context*.xml</param-value>中的xml文件

    static {
		try {
			ClassPathResource resource = new ClassPathResource("ContextLoader.properties", ContextLoader.class);
			defaultStrategies = PropertiesLoaderUtils.loadProperties(resource);
		}
		catch (IOException ex) {
			throw new IllegalStateException("Could not load 'ContextLoader.properties': " + ex.getMessage());
		}
	}

  

   8.ContextLoader.properties 文件內容如下:

  org.springframework.web.context.WebApplicationContext=org.springframework.web.context.support.XmlWebApplicationContext

  此時,determineContextClass( )方法返回的是XmlWebApplicationContext對象,之后回到3步驟中的configureAndRefreshWebApplicationContext( )方法

 

  9.  configureAndRefreshWebApplicationContext的細節調用

    configureAndRefreshWebApplicationContext 調用了AbstractApplicationContext的refresh方法

    refresh 方法調用了obtainFreshBeanFactory

    obtainFreshBeanFactory 調用了AbstractRefreshableApplicationContext類的refreshBeanFactory方法

    refreshBeanFactory調用了XmlWebApplicationContext的loadBeanDefinitions

    loadBeanDefinitions中加載了對應的applicationContext.xml

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM