SPRING 啟動載入BEAN 的程式碼過程
當Web應用啟動時,contextInitialized方法會執行載入根上下文(IOC容器):
(1)spring的web專案啟動的時候會,啟動我們常用的監聽類。
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>WEB-INF/classes/spring-context.xml</param-value>
</context-param>
<!-- Spring監聽器 -->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
(2)tomcat在載入web應用時候,會針對每個web.xml的監聽器進行建立,看org.apache.catalina.core.StandardContext.listenerStart(),
public
boolean listenerStart() {
if (log.isDebugEnabled())
log.debug("Configuring application event listeners");
String listeners[] = findApplicationListeners();
Object results[] = new Object[listeners.length];
boolean ok = true;
for (int i = 0; i < results.length; i++) {
if (getLogger().isDebugEnabled())
getLogger().debug(" Configuring event listener class '" + listeners[i] + "'");
try {
String listener = listeners[i];
results[i] = getInstanceManager().newInstance(listener);
} catch (Throwable t) {
t = ExceptionUtils.unwrapInvocationTargetException(t);
ExceptionUtils.handleThrowable(t);
getLogger().error(sm.getString("standardContext.applicationListener", listeners[i]), t);
ok = false;
}
}
if (!ok) {
getLogger().error(sm.getString("standardContext.applicationSkipped"));
return (false);
}
ArrayList<Object> eventListeners = new ArrayList<>();
ArrayList<Object> lifecycleListeners = new ArrayList<>();
for (int i = 0; i < results.length; i++) {
if ((results[i] instanceof ServletContextAttributeListener)
|| (results[i] instanceof ServletRequestAttributeListener)
|| (results[i] instanceof ServletRequestListener)
|| (results[i] instanceof HttpSessionIdListener)
|| (results[i] instanceof HttpSessionAttributeListener)) {
eventListeners.add(results[i]);
}
if ((results[i] instanceof ServletContextListener)
|| (results[i] instanceof HttpSessionListener)) {
lifecycleListeners.add(results[i]);
}
}
for (Object eventListener : getApplicationEventListeners()) {
eventListeners.add(eventListener);
}
setApplicationEventListeners(eventListeners.toArray());
for (Object lifecycleListener : getApplicationLifecycleListeners()) {
lifecycleListeners.add(lifecycleListener);
if (lifecycleListener instanceof ServletContextListener) {
noPluggabilityListeners.add(lifecycleListener);
}
}
setApplicationLifecycleListeners(lifecycleListeners.toArray());
if (getLogger().isDebugEnabled())
getLogger().debug("Sending application start events");
getServletContext();
context.setNewServletContextListenerAllowed(false);
Object instances[] = getApplicationLifecycleListeners();
if (instances == null || instances.length == 0) {
return ok;
}
ServletContextEvent tldEvent = null;
if (noPluggabilityListeners.size() > 0) {
noPluggabilityServletContext = new NoPluggabilityServletContext(getServletContext());
tldEvent = new ServletContextEvent(noPluggabilityServletContext);
}
for (int i = 0; i < instances.length; i++) {
if (!(instances[i] instanceof ServletContextListener))
continue;
ServletContextListener listener = (ServletContextListener) instances[i];
try {
fireContainerEvent("beforeContextInitialized", listener);
if (noPluggabilityListeners.contains(listener)) {
listener.contextInitialized(tldEvent);
} else {
listener.contextInitialized(event);
}
fireContainerEvent("afterContextInitialized", listener);//註冊事件
} catch (Throwable t) {
ExceptionUtils.handleThrowable(t);
fireContainerEvent("afterContextInitialized", listener);
getLogger().error(sm.getString("standardContext.listenerStart", instances[i].getClass().getName()), t);
ok = false;
}
}
return (ok);
}
(3)具體的建立wepapplicationcontext的過程如下:
ContextLoaderListener.contextInitialized(ServletContextEvent event)
->ContextLoader.initWebApplicationContext(ServletContext servletContext)
->ContextLoader.createWebApplicationContext(ServletContext sc) - - - - - 如果web.xml裡沒指定型別,預設是XmlWebAppalication
->ContextLoader.configureAndRefreshWebApplicationContext(ConfigurableWebApplicationContext wac, ServletContext sc) - - - - - - 配置和初始化 webApplicationContext
->ConfigurableWebApplicationContext.refresh() - - - - - ConfigurableWebApplicationContext是介面
->AbstractApplicationContext.refresh() - - - - - 啟動 容器初始化
->AbstractApplicationContext.obtainFreshBeanFactory() - - - - - 建立BeanFactory,開始容器的初始化過程,比如BeanDefinition的載入
->AbstractRefreshableApplicationContext.refreshBeanFactory() - - - - - 在這裡建立了BeanFactory(DefaultListableBeanFactory)。然後開始loadBeanDefinitions,這是一個抽象方法,實際的載入是在XmlWebApplicationContext類裡。
->XmlWebApplicationContext.loadBeanDefinitions(DefaultListableBeanFactory beanFactory) - - - -建立一個XmlBeanDefinitionReader,並啟動bean定義資訊的載入。
->XmlWebApplicationContext.loadBeanDefinitions(XmlBeanDefinitionReader reader) - - - 根據配置檔案的locations,因為配置檔案是xml的,所以使用的是XmlBeanDefinitionReader 。具體的載入過程是委託給BeanDefinitionReader完成的
->AbstractBeanDefinitionReader.loadBeanDefinitionReader - - - 這是一個抽象類,實際的載入是在XmlBeanDefinitionReader中實現的,抽象類是根據bean定義的xml配置檔案的路徑,生成resource。然後XmlBeanDefinitionReader根據resource開始具體載入BeanDefinition
->XmlBeanDefinitionReader.loadBeanDefinitionReader(Resource resource)
->XmlBeanDefinitionReader.loadBeanDefinitions(EncodedResource encodedResource) - - - 在讀取器中,需要得到代表XML檔案的resource,這個resource物件封裝了對xml檔案的IO操作,所以讀取器可以在開啟IO流後得到XML的檔案物件。
->XmlBeanDefinitionReader.doLoadBeanDefinitions(InputSource inputSource, Resource resource) - - - -讀取器在這裡開啟IO流後得到XML的檔案Document物件(Document物件是通過XML解析器出來的,下面會再根據Spring Bean的規則再解析出BeanDefinition)。得到物件後就可以按照spring的Bean定義規則來對這個xml的檔案檔樹進行解析了
->XmlBeanDefinitionReader.registerBeanDefinitions(Document doc, Resource resource) - - -這個方法啟動對BeanDefinition的解析的詳細過程,這個解析會使用到Spring的Bean的配置規則。具體的過程是有BeanDefinitionDocumentReader來完成的。
->BeanDefinitionDocumentReader.registerBeanDefinitions(Document doc, XmlReaderContext readerContext)
->DefaultBeanDefinitionDocumentReader.registerBeanDefinitions(Document doc, XmlReaderContext readerContext) - - - - -DefaultBeanDefinitionDocumentReader 是BeanDefinitionDocumentReader的實現類,registerBeanDefinitions方法開始按照Spring
Bean的規則解析Document物件
->DefaultBeanDefinitionDocumentReader.doRegisterBeanDefinitions(Element root) - - -解析過程是由BeanDefinitionParserDelegate物件來完成的。
->DefaultBeanDefinitionDocumentReader.parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate)
->DefaultBeanDefinitionDocumentReader.parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate)
->DefaultBeanDefinitionDocumentReader.processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate)
- - - - 解析的結果是由BeanDefinitionHolder來持有的,這個BeanDefinitionHolder物件封裝了BeanDefinition,beanName,aliases等資訊,用它來完成向IOC容器註冊。
->BeanDefinitionParserDelegate.parseBeanDefinitionElement(Element ele)
->BeanDefinitionParserDelegate.parseBeanDefinitionElement(Element ele, BeanDefinition containingBean)
->BeanDefinitionParserDelegate.parseBeanDefinitionElement(
Element ele, String beanName, BeanDefinition containingBean) - - - 對xml配置檔案中的配置的Bean進行詳細解析,這裡只是讀取定義 的<bean>,並載入到BeanDefinition中去,這裡不涉及物件的例項化過程,物件的例項化實際上是再依賴注入時完成的。