一、????????????
概述
二、????????????
Spring
初始化之旅
a)????????
Spring
初始化的時候首先要運行的類為:
org.springframework.web.context. ContextLoaderListener
或
org.springframework.web.context. ContextLoaderServlet
。
??????
它們在初始化函數里無一例外地實例化了
ContextLoader
類
,
然后調用了它的函數
???? public WebApplicationContext initWebApplicationContext(ServletContext )
。
??????
接下來看一下在這個方法里干了寫什么
b)???????
在他的方法體內,關鍵是“
this.context = createWebApplicationContext(servletContext, parent);
”新建了一個“
ConfigurableWebApplicationContext
”類型的對象,在這一步實例化中幾乎完成了所有的
spring
初始化工作。讀取了所有的
spring
配置文件。它的工作步驟如下所述。
c)???????
首先,在將“
ConfigurableWebApplicationContext
”類型的對象實例化以后(這個對象實際的類型是這個包內的
XmlWebApplicationContext
),然后又給這個實例設置了三個屬性,“
wac.setParent(parent);
”在默認的初始化過程中這一步設置了一個
null
值,然后又設置了一個“
wac.setServletContext(servletContext);
”,將系統默認的上下文設置進來,比較重要的是下面這一段:
??????????
?????? if (configLocation != null) {
?????? //
讀取
spring
的應用配置文件
?????? wac.setConfigLocations(StringUtils.tokenizeToStringArray(configLocation,Configurabl?????? eWebApplicationContext.CONFIG_LOCATION_DELIMITERS));
?????? }
??????
它將我們的配置文件名放置到
wac
變量中,以待在后續的操作中使用。然后調用
?????????
“
wac.refresh();
”完成主要的初始化
BeanFactory
的操作。如下。
d)???????
首先我們應該看一下我們實例化的對象
?????? org.springframework.web.context.support.XmlWebApplicationContext
的類圖:
?
e)????????
“
wac.refresh();
”從類結構里我們能找到這個方法來自它的父類:
AbstractApplicationContext
在它的
refresh()
方法內我們可以看到
spring
的復雜邏輯。
??????
首先執行了
refreshBeanFactory();
(來自
AbstractRefreshableApplicationContext
)見
f),
f)????????
refreshBeanFactory();
這個方法由負責維護變量
beanFactory
的子類
AbstractRefreshableApplicationContext
實現,默認情況下這個方法直接實例化一個新的
DefaultListableBeanFactory
類型的
BeanFacorty,
然后調用一個起緩沖作用的配置函數生成一個將
beanFacroty
包裝起來的對象
beanDefinitionReader
,然后對這個對象進行屬性配置,實際上該方法主要負責生成一個臨時的操作對象,對應調用的函數為“
loadBeanDefinitions(beanFactory);
”該方法為初始化期間較為重要的一個。
??????
該方法來自其子類:
AbstractRefreshableWebApplicationContext
對應的函數:
protected void loadBeanDefinitions(DefaultListableBeanFactory)
,然后這里又調用了自己定義的
protected void loadBeanDefinitions(XmlBeanDefinitionReader)
方法。此時,它就使用到了在
c)
中設置了的(
wac.setConfigLocations(……))
我們開發中密切相關的配置文件。(同時也要記住此時這個函數的參數
beanDefinitionReader
,之前已經設置了“
beanDefinitionReader.setResourceLoader(this);
”這里的
this
是我們在前面見到的
XmlWebApplicationContext
(一個定義好了的上下文))。接著往下:
??????
“
reader.loadBeanDefinitions(configLocations[i]);
”
reader
開始加載我們配置文件內的東西了,不過真正復雜的實現此時才開始,我們繼續往下走,在接下來的方法內默認情況下會執行:
if (resourceLoader instanceof ResourcePatternResolver)
(該判斷條件為
true
)
,
由于從上面我們知道:
beanDefinitionReader.setResourceLoader(this);
而
this
的類型為:
XmlWebApplicationContext
所以
((ResourcePatternResolver) resourceLoader).getResources(location);
得到一個
Resource[]
數組,接下來調用:
int loadCount = loadBeanDefinitions(resources);
該函數繼續調用自己子類定義的一系列臨時接口最終執行到
return doLoadBeanDefinitions(inputSource, encodedResource.getResource());
在這個函數內初始化了處理
xml
文件的一些對象并將用戶的配置文件解析為一個
Document
對象。然后又執行了一系列函數直到
return parser.registerBeanDefinitions(this, doc, resource);
這個函數來自我們新建的
DefaultXmlBeanDefinitionParser
,在這個類里最終執行了對
xml
文件的解析工作和對
beanFacroty
變量執行了設置工作。
g)???????
終于我們從這些繁雜的邏輯中跳了出來,繼續執行
AbstractApplicationContext.refresh()
下面的工作,后續的代碼主要仍舊是往一些常量里面設值。
此時
spring
初始化過程就結束了。