Spring 最重要的方法refresh方法
根據上一篇文章 https://www.cnblogs.com/redwinter/p/16141285.html Spring Bean IOC
的建立流程繼續解讀Spring
原始碼,本篇文章解讀Spring
原始碼最重要的方法refresh
方法。
這個方法位於:AbstractApplicationContext#refresh,這個方法中總共有15個方法,Spring原始碼的精髓就是這15個方法中。
@Override
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// Prepare this context for refreshing.
// 準備工作,載入環境變數等操作
// 1、設定容器啟動時間
// 2、設定停止狀態為false
// 3、設定活躍狀態為true
// 4、獲取Environment物件,並設定屬性值
// 5、設定監聽器和事件的集合,模式為空的集合
prepareRefresh();
// Tell the subclass to refresh the internal bean factory.
// 告訴子類重新整理內部 bean 工廠, 獲取重新整理bean的工廠: DefaultListableBeanFactory
// 並且載入BeanDefinition
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.
// 允許子類進行擴充套件BeanFactoryPostProcessor
postProcessBeanFactory(beanFactory);
// Invoke factory processors registered as beans in the context.
// 例項化並執行BeanFactoryPostProcessor
invokeBeanFactoryPostProcessors(beanFactory);
// Register bean processors that intercept bean creation.
// 例項化並註冊BeanPostProcessor
registerBeanPostProcessors(beanFactory);
// Initialize message source for this context.
// 國際化設定
initMessageSource();
// Initialize event multicaster for this context.
// 例項化事件多播器
initApplicationEventMulticaster();
// Initialize other special beans in specific context subclasses.
// 初始化特定上下文子類中的其他特殊bean,web容器
onRefresh();
// Check for listener beans and register them.
// 檢查listener bean 並註冊它們
// 註冊監聽器
registerListeners();
// Instantiate all remaining (non-lazy-init) singletons.
// 例項化所有剩餘的(非惰性初始化)單例。
finishBeanFactoryInitialization(beanFactory);
// Last step: publish corresponding event.
// 釋出相應的事件
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.
// 銷燬Bean
destroyBeans();
// Reset 'active' flag.
// 重置 active 標誌
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();
}
}
}
前戲準備 prepareRefresh 方法
Spring的前戲準備大概就是做了以下幾件事:
- 設定容器的啟動時間
- 設定容器的停止狀態為false
- 設定容器的啟用狀態為true
- 獲取環境資訊並驗證必要的屬性
- 準備監聽器和事件的容器
protected void prepareRefresh() {
// Switch to active.
// 設定啟動時間 設定標識位
this.startupDate = System.currentTimeMillis();
// 設定容器停止標識為false
this.closed.set(false);
// 設定容器啟用標識為true
this.active.set(true);
// Initialize any placeholder property sources in the context environment.
// 初始化上下文環境中的任何佔位符屬性源
// 留給子類進行擴充套件,比如新增必須的屬性值驗證
initPropertySources();
// Validate that all properties marked as required are resolvable:
// see ConfigurablePropertyResolver#setRequiredProperties
// 獲取環境物件,並驗證需要的屬性
getEnvironment().validateRequiredProperties();
// Store pre-refresh ApplicationListeners...
// 準備應用監聽器和實踐的容器初始化
if (this.earlyApplicationListeners == null) {
this.earlyApplicationListeners = new LinkedHashSet<>(this.applicationListeners);
}
else {
// Reset local application listeners to pre-refresh state.
// 如果不為空,那麼就清空掉,並設定新的早期的監聽器進去
this.applicationListeners.clear();
this.applicationListeners.addAll(this.earlyApplicationListeners);
}
// Allow for the collection of early ApplicationEvents,
// to be published once the multicaster is available...
this.earlyApplicationEvents = new LinkedHashSet<>();
}
這裡有個問題就是他的環境資訊是何時設定進去的呢?
實際上是在容器啟動時呼叫了父類建構函式時設定進去的,Environment
他是一個介面,他有個重要的實現類叫StandardEnvironment
,在Spring啟動的時候就會使用這個類進行環境資訊的載入,最終他會呼叫到System#getProperties
和System#getenv
方法,然後將載入到屬性放在Map中進行儲存。
大概的流程如下:
標記的類就是Environment
環境資訊的載入過程呼叫的類,最終會呼叫到System#getProperties
和System#getenv
方法,然後完成環境資訊的載入,主要載入的資訊就是系統的環境變數,比如在Windows
中配置的環境變數或者啟動類中使用-D
引數配置的啟動引數都會進行載入到StandardEnvironment
這個類中,類似於使用-Dxxx.name=123
這種引數會載入到systemProperties
中,配置的windows
環境變數會載入systemEnvironment
中。
這個就是Spring IOC
建立的第一個方法的前戲準備工作,接下來解讀預設的BeanFactory
實現類DefaultListableBeanFactory
的建立過程。