1.根據我們常用的web.xml裡,我們找到的org.springframework.web.context.ContextLoaderListener。web.xml如下
<?xml version="1.0" encoding="UTF-8"?>
<web-app
version="3.0"
xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd">
<display-name>moon</display-name>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
classpath*:applicationContext.xml
</param-value>
</context-param>
</web-app>
- 其實ContextLoaderListener是一個ServletContextListener,一個web容器的監聽器。根據其父類org.springframework.web.context.ContextLoader初始化的策略配置,找到類目錄下面的ContextLoader.properties檔案。裡面配置著一個Spring上下文類。
# Default WebApplicationContext implementation class for ContextLoader.
# Used as fallback when no explicit context implementation has been specified as context-param.
# Not meant to be customized by application developers.
org.springframework.web.context.WebApplicationContext=org.springframework.web.context.support.XmlWebApplicationContext
額外知識點:
參考《ClassPathResource知識點》
- 載入策略資源(ContextLoader.properties)後,web容器啟動時會呼叫ContextLoaderListener的contextInitialized方法。
- contextInitialized方法裡初始化ContextLoader.properties配置的org.springframework.web.context.support.XmlWebApplicationContext,這個初始化過程有點長。
4.1 從ServletContext獲取物件springcontext物件,如果存在則拋異常。key=org.springframework.web.context.WebApplicationContext.ROOT
4.2 從ContextLoader.properties獲取className=org.springframework.web.context.support.XmlWebApplicationContext
4.3 通過ClassUtils工具例項化spring的ApplicationContext,我們能夠看出他是使用ContextLoader類的類載入器,這裡有個可以弄個知識點《ClassUtils知識點》
ClassUtils.forName(contextClassName, ContextLoader.class.getClassLoader())
4.4 XmlWebApplicationContext例項化時,其一些列父類也將初始化和例項化(我稍微地簡化說,具體的可以看原始碼):
層次 | 類名 | 作用 |
---|---|---|
第0層 | org.springframework.web.context.support.XmlWebApplicationContext | 定義預設配置檔案,如/WEB-INF/applicationContext.xml |
第1層 | org.springframework.web.context.support.AbstractRefreshableWebApplicationContext | 宣告瞭ServletContext servletContext和ServletConfig servletConfig |
第2層 | org.springframework.context.support.AbstractRefreshableConfigApplicationContext | 此時就跟web沒多大關係了,定義了配置變數String[] configLocations |
第3層 | org.springframework.context.support.AbstractRefreshableApplicationContext | 此層就重要了,定義了DefaultListableBeanFactory beanFactory |
第4層 | org.springframework.context.support.AbstractApplicationContext | 此層定義了父context,還有ApplicationContext的其他配置等,refresh()方法 |
第5層 | org.springframework.core.io.DefaultResourceLoader | 此層與ApplicationContext沒多大關係,從包名也能看出,宣告瞭ClassLoader |
第6層(最後一層) | org.springframework.core.io.ResourceLoader | spring的作者的註釋是Strategy interface for loading resources,嗯哈,大概猜是使用策略模式的介面 |
-
例項化完XmlWebApplicationContext類後,就開始做點事情了。在ContextLoader裡,有個方法configureAndRefreshWebApplicationContext(cwac, servletContext),從方法名就能看出是配置和重新整理ApplicationContext。
5.1 設定ServletContext,參考第1層
5.2 設定configLocations,參考第2層,這裡又一個知識點《StringUtils知識點》
5.3 呼叫AbstractRefreshableWebApplicationContext的createEnvironment()方法來初始化StandardServletEnvironment物件。參考知識點《StandardServletEnvironment知識點》
5.4 呼叫StandardServletEnvironment物件initPropertySources(ServletContext servletContext, ServletConfig servletConfig)方法來獲取web容器所有配置資訊。配置資訊都在放在StandardServletEnvironment物件的MutablePropertySources物件裡。
5.5 customizeContext(sc, wac)自定義初始化applicationContext的一些資訊,裡面是獲取實現org.springframework.context.ApplicationContextInitializer介面的一些方法呼叫。一個知識點也誕生《ApplicationContextInitializer知識點》5.6 重頭戲來了,refresh ApplicationContext!!!,呼叫第4層的refresh()方法。
5.6.1 第一步:載入ServletContext和ServletConfig引數,並使用PropertySourcesPropertyResolver校驗是否有必須的配置缺失,可參考知識點《PropertySourcesPropertyResolver知識點》。 5.6.2 第二步:例項化BeanFactory,交給子類AbstractRefreshableApplicationContext來例項化(參考第3層),例項化了org.springframework.beans.factory.support.DefaultListableBeanFactory物件作為變數beanFactory的值。並配置是否允許覆蓋bean和是否允許迴圈引用,預設都是否。 5.6.3 第三步:第3層AbstractRefreshableApplicationContext去loadBeanDefinitions,loadBeanDefinitions方法被子類XmlWebApplicationContext覆寫了,建立org.springframework.beans.factory.xml.XmlBeanDefinitionReader物件進行載入Bean的定義。這個是重點核心的知識點,參考《XmlBeanDefinitionReader知識點》。 看到這裡應該知道每一層ApplicationContext的作用吧,一層一層往上遞進 5.6.4 第四步: //TODO 正在研讀XmlBeanDefinitionReader
- //TODO