Spring 最重要的方法refresh方法 根據上一篇文章 https://www.cnblogs.com/redwinter/p/16141285.html Spring Bean IOC 的創建流程繼續解讀Spring源碼,本篇文章解讀Spring 源碼最重要的方法refresh方法。 這個方 ...
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
的創建過程。