Spring源碼-容器如何初始化?
初始化Spring如下
AbstractApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");
applicationContext.start();
查看源碼:
public ClassPathXmlApplicationContext(String configLocation) throws BeansException {
this(new String[] {configLocation}, true, null);
}
/**
* Create a new ClassPathXmlApplicationContext with the given parent,
* loading the definitions from the given XML files.
* @param configLocations array of resource locations
* @param refresh whether to automatically refresh the context,
* loading all bean definitions and creating all singletons.
* Alternatively, call refresh manually after further configuring the context.
* @param parent the parent context
* @throws BeansException if context creation failed
* @see #refresh()
*/
/**
第一個參數是 spring的配置文件可能是多個
第二個參數是 是否自動刷新容器,加載所有定義並創建所有單例。否則,在更多其他配置操作後,手動刷新容器
第三個參數 parent null
*/
public ClassPathXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent)
throws BeansException {
// 調用父類構造器
super(parent);
// 配置文件相關
setConfigLocations(configLocations);
if (refresh) {
refresh();
}
}
主要是通過refresh進行bean的初始化
@Override
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// Prepare this context for refreshing.
// 準備刷新的上下文環境
prepareRefresh();
// Tell the subclass to refresh the internal bean factory.
// 初始化BeanFactory,並進行XML文件讀取
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// Prepare the bean factory for use in this context.
// 對BeanFactory進行各種功能填充
prepareBeanFactory(beanFactory);
try {
// Allows post-processing of the bean factory in context subclasses.
// 子類覆蓋方法做額外處理
postProcessBeanFactory(beanFactory);
// Invoke factory processors registered as beans in the context.
// 激活各種BeanFactory處理器
invokeBeanFactoryPostProcessors(beanFactory);
// Register bean processors that intercept bean creation.
// 註冊攔截Bean 創建Bean的處理器,這裏只是註冊,真正調用的是getBean的時候
registerBeanPostProcessors(beanFactory);
// Initialize message source for this context.
// 爲上下文初始化Message源, 不同語言的消息體,國際化處理
initMessageSource();
// Initialize event multicaster for this context.
//初始化消息廣播器,並放入applicationEventMulticastBean中
initApplicationEventMulticaster();
// Initialize other special beans in specific context subclasses.
//留給子類來初始化其他的bean
onRefresh();
// Check for listener beans and register them.
// 在所有註冊的bean中,查找 Listener Bean 註冊到廣播消息中
registerListeners();
// Instantiate all remaining (non-lazy-init) singletons.
// 初始化生效的單實例(非惰性的)
finishBeanFactoryInitialization(beanFactory);
// Last step: publish corresponding event.
// 完成刷新過程,通知生命週期處理器LifecycleProcessor刷新過程,同時發出ContextRefreshEvent通知別人
finishRefresh();
}
catch (BeansException ex) {
if (logger.isWarnEnabled()) {
logger.warn("Exception encountered during context initialization - " +
"cancelling refresh attempt: " + ex);
}
// Destroy already created singletons to avoid dangling resources.
destroyBeans();
// Reset 'active' flag.
cancelRefresh(ex);
// Propagate exception to caller.
throw ex;
}
finally {
// Reset common introspection caches in Spring's core, since we
// might not ever need metadata for singleton beans anymore...
resetCommonCaches();
}
}
}
總結下ClasspathXmlApplicationContext初始化過程
- 初始化前的準備工作,例如對系統屬性或者環境變量進行準備驗證,在某些情況下項目的使用需要讀取某些系統變量,prepareRefresh()這個變量就顯得十分必要
- 初始化BeanFacory 對xml文件進行讀取
- 對BeanFactory進行各種功能填充. @Autowried和@Qualifier就是這時填充的
- 子類覆蓋方法做額外的處理
- 激活各種BeanFactory處理器。
- 註冊攔截bean創建的bean處理器,這裏只是註冊,真正的調用是在getBean時候。
- 爲上下文初始化Message源,即對不同語言的消息體進行國際化處理。
- 初始化應用消息廣播器,並放入“applicationEvent-Multicaster”bean中。
- 留給子類來初始化其他的bean。
- 在所有註冊的bean中查找listener bean,註冊到消息廣播器中。
- 初始化剩下的單實例(非惰性的)。
- 完成刷新過程,通知生命週期處理器lifecycleProces-sor刷新過程,同時發出Context RefreshEvent通知別人。
@Autowired默認是根據類型進行注入的,因此如果有多個類型一樣的Bean候選者,則需要限定其中一個候選者,否則將拋出異常
@Qualifier限定描述符除了能根據名字進行注入,更能進行更細粒度的控制如何選擇候選者,具體使用方式如下:
初始化前的準備工作prepareRefresh()
protected void prepareRefresh() {
this.startupDate = System.currentTimeMillis();
this.closed.set(false);
this.active.set(true);
if (logger.isInfoEnabled()) {
logger.info("Refreshing " + this);
}
// Initialize any placeholder property sources in the context environment
//初始化環境變量參數 留給子類覆蓋initPropertySources()空的,沒有任何邏輯
initPropertySources();
// Validate that all properties marked as required are resolvable
// see ConfigurablePropertyResolver#setRequiredProperties
// 驗證需要的屬性文件是否都放入環境中
getEnvironment().validateRequiredProperties();
// Allow for the collection of early ApplicationEvents,
// to be published once the multicaster is available...
this.earlyApplicationEvents = new LinkedHashSet<ApplicationEvent>();
}
關注兩個函數
(1)initPropertySources正符合Spring的開放式結構設計,給用戶最大擴展Spring的能力。用戶可以根據自身的需要重寫initPropertySources方法,並在方法中進行個性化的屬性處理及設置。
(2)validateRequiredProperties則是對屬性進行驗證,那麼如何驗證呢?我們舉個融合兩句代碼的小例子來幫助大家理解。
加載BeanFactory的obtainFreshBeanFactory()方法
protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
refreshBeanFactory();
ConfigurableListableBeanFactory beanFactory = getBeanFactory();
if (logger.isDebugEnabled()) {
logger.debug("Bean factory for " + getDisplayName() + ": " + beanFactory);
}
return beanFactory;
}
參考資料