Spring IOC原始碼(一):IOC容器啟動流程核心方法概覽
阿新 • • 發佈:2022-12-10
Spring有兩種方式載入配置,分別為xml檔案、註解的方式,對於xml配置的方式相信大家都不陌生,往往通過new ClassPathXmlApplicationContext("*.xml")就能啟動容器了,下面讓我們來看看Spring的容器啟動都做了哪些事情。
1、ClassPatchXmlApplicationContext的類圖結構
從類圖我們可以得到的資訊: 1,ClassPatchXmlApplicationContext是一個容器 ,是BeanFactory的子類; 2,ClassPatchXmlApplicationContext是一個資源載入器,是ResourceLoader的子類。2、ClassPatchXmlApplicationContext構造器
1 public ClassPathXmlApplicationContext( 2 String[] configLocations, boolean refresh, @Nullable ApplicationContext parent) 3 throws BeansException { 4 // 呼叫父類構造方法 5 super(parent); 6 // 資源路徑設定到當前上下文中 7 setConfigLocations(configLocations); 8 // 重新整理容器 9 if (refresh) { 10 refresh(); 11 } 12 }
2.1、呼叫父類構造器
最終會呼叫到父類AbstractApplicationContext的構造方法。 1、初始化AbstractApplicationContext的資源路徑解析器resourcePatternResolver 屬性; 2、為當前上下文設定父上下文環境,若父上下文環境不為空,將父上下文環境合併到當前上下文環境中。1 // 構造器 2 public AbstractApplicationContext(@Nullable ApplicationContext parent) { 3 this(); 4 setParent(parent); 5 } 6 // 初始化資源路徑解析器 7 public AbstractApplicationContext() { 8 // 建立資源模式處理器 9 this.resourcePatternResolver = getResourcePatternResolver(); 10 } 11 // 設定父容器 12 public void setParent(@Nullable ApplicationContext parent) { 13 this.parent = parent; 14 // 若父容器不為空,則將父容器的環境配置合併到當前容器中 15 if (parent != null) { 16 Environment parentEnvironment = parent.getEnvironment(); 17 if (parentEnvironment instanceof ConfigurableEnvironment) { 18 getEnvironment().merge((ConfigurableEnvironment) parentEnvironment); 19 } 20 } 21 }
2.2、設定資源路徑
對父類AbstractRefreshableConfigApplicationContext的configLocations做賦值,將配置資源配置檔案位置設定到當前應用程式上下文中。1 // 設定資源路徑 2 public void setConfigLocations(@Nullable String... locations) { 3 if (locations != null) { 4 Assert.noNullElements(locations, "Config locations must not be null"); 5 this.configLocations = new String[locations.length]; 6 for (int i = 0; i < locations.length; i++) { 7 this.configLocations[i] = resolvePath(locations[i]).trim(); 8 } 9 } 10 else { 11 this.configLocations = null; 12 } 13 }
2.3、重新整理容器 - Spring的IOC容器的核心啟動流程
1 // 重新整理容器的流程 2 @Override 3 public void refresh() throws BeansException, IllegalStateException { 4 synchronized (this.startupShutdownMonitor) { 5 // 容器重新整理前的準備工作 6 prepareRefresh(); 7 // 建立容器物件DefaultListableBeanFactory,載入xml配置檔案的屬性值到當前工廠中 8 ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory(); 9 // beanFactory的準備工作,對各種屬性進行填充 10 prepareBeanFactory(beanFactory); 11 12 try { 13 // 子類覆蓋方法做額外的處理,web中的程式碼有具體實現 14 postProcessBeanFactory(beanFactory); 15 16 // 呼叫各種beanFactory處理器 17 invokeBeanFactoryPostProcessors(beanFactory); 18 19 // 註冊bean處理器,這裡只是註冊功能,真正呼叫的地方在getBean方法 20 registerBeanPostProcessors(beanFactory); 21 22 // 為上下文初始化message源,即不同語言的訊息體,國際化處理,在springmvc的有實際應用 23 initMessageSource(); 24 25 // 初始化事件監聽多路廣播器 26 initApplicationEventMulticaster(); 27 28 // 留給子類來初始化其他的bean 29 onRefresh(); 30 31 // 在所有註冊的bean中查詢listener bean,註冊到訊息廣播器中 32 registerListeners(); 33 34 // 初始化剩下的單例項(非懶載入的) 35 finishBeanFactoryInitialization(beanFactory); 36 37 // 完成重新整理過程,通知生命週期處理器lifecycleProcessor重新整理過程,同時發出ContextRefreshEvent通知 38 finishRefresh(); 39 } 40 41 catch (BeansException ex) { 42 if (logger.isWarnEnabled()) { 43 logger.warn("Exception encountered during context initialization - " + 44 "cancelling refresh attempt: " + ex); 45 } 46 47 // 為防止bean資源佔用,在異常處理中,銷燬已經在前面過程中生成的單件bean 48 destroyBeans(); 49 50 // 重置active標誌 51 cancelRefresh(ex); 52 53 throw ex; 54 } 55 finally { 56 // 重置快取 57 resetCommonCaches(); 58 } 59 } 60 }
綜上可見,Spring容器啟動的核心方法,這些方法後序會做詳細介紹