看了一星期的Spring源碼,把refresh()方法從頭至尾梳理了一遍,在看的過程中想記錄一些關鍵點,但是需要記錄的東西太多,有種無從下手的感覺。因為我在看源碼的過程中遇到了很多的疑惑,這些疑惑有時候是一個零散的點,比如動態代理(jdk動態代理和cglib動態代理)、設計模式,有時候是一個很長的鏈,比如一個完整的bean的創建過程,即bean的生命周期,有時候又是一個很廣的面,比如IOC和AOP的原理,發現、思考和解決種種疑惑的過程中,我對Spring有了一個全新的認知。說實話,讓我感覺以前的開發真的只是停留在了“用”的層面,因為Spring它真的強大到95%的開發中都不需要開發人員知道它的設計原理,只要進行黑盒開發即可,在看源碼的過程中就會發現平時自己一個小小的舉動,在源碼中都可以追溯到它的前世今生,真的會感知到並驚嘆程序設計之美!在寫之前我糾結過一些問題,是先補充一些看源碼的前置知識點,還是在遇到需要知道的前置知識時再補充,這就有點像單例模式的餓漢式和懶漢式了,我糾結的點在於:如果用餓漢式,就很難舉例子說明其在spring中的應用,比如設計模式;如果用懶漢式,又顯得邏輯跳來跳去,容易讓思想陷入死循環,就像看源碼時看一個方法的實現,如果對每一個方法的所有細節都刨根問底,見到方法就點進去,看着看着就會陷入無限循環中,從而失去最初的興趣,鑒於這兩種糾結,我決定將兩種方式結合起來,出一個滲透spring源碼的系列博客,先梳理整體情況,再說明前置知識點,最后跟源碼,在源碼解析中用到的知識點,以鏈接的形式加入,在前置知識點中可能提及的源碼,也以鏈接的形式加入,而不是在當前文章中另起段落,這就有點像循環引用了,哈哈~
本系列博客的規划如下:
-
細讀Spring源碼(一)---refresh()方法概覽
-
細讀Spring源碼(二)---關於Spring中用到的設計模式
-
細讀Spring源碼(三)---深度剖析動態代理底層實現
-
細讀Spring源碼(四)---什么是IOC?
-
細讀Spring源碼(五)---AOP從實戰到源碼
-
細讀Spring源碼(六)---關於源碼設計架構
-
細讀Spring源碼(七)---關於Spring中的核心接口
-
細讀Spring源碼(八)---prepareRefresh()
-
細讀Spring源碼(九)---obtainFreshBeanFactory()
-
細讀Spring源碼(十)---prepareBeanFactory(beanFactory)
-
細讀Spring源碼(十一)---postProcessBeanFactory(beanFactory)
-
細讀Spring源碼(十二)---invokeBeanFactoryPostProcessors(beanFactory)
-
細讀Spring源碼(十三)---registerBeanPostProcessors(beanFactory)
-
細讀Spring源碼(十四)---beanPostProcess.end()
-
細讀Spring源碼(十五)---initMessageSource()
-
細讀Spring源碼(十六)---initApplicationEventMulticaster()
-
細讀Spring源碼(十七)---onRefresh()
-
細讀Spring源碼(十八)---registerListeners()
-
細讀Spring源碼(十九)---finishBeanFactoryInitialization(beanFactory)
-
細讀Spring源碼(二十)---ffinishRefresh()
閱讀Spring的源碼,可以通過下面的方式開啟調試:
1 public static void main(String[] args) { 2 ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("classpath:spring.xml"); 3 UserVo userVo = context.getBean(UserVo.class); 4 EnterpriseVo enterpriseVo = context.getBean(EnterpriseVo.class); 5 System.out.println("userVo=" + userVo); 6 System.out.println("enterpriseVo=" + enterpriseVo); 7 context.close(); 8 }
主要是上面的第2行開始,進入該方法會進入下面的方法:
1 public ClassPathXmlApplicationContext(String[] configLocations, boolean refresh, @Nullable ApplicationContext parent) throws BeansException { 2 super(parent); 3 this.setConfigLocations(configLocations); 4 if (refresh) { 5 this.refresh(); 6 } 7 8 }
第3行是設置配置文件,即為傳遞的classpath:spring.xml
第5行就是今天要說的refresh()方法,這是spring容器啟動的入口所在,因為該方法中總共有13個子方法,所以今天只是看一下概覽,后續對每個方法進行跟進
通過一張思維導圖說明每個方法主要完成的事情:
下面是源碼中的添加的注釋:
1 public void refresh() throws BeansException, IllegalStateException { 2 synchronized (this.startupShutdownMonitor) { 3 StartupStep contextRefresh = this.applicationStartup.start("spring.context.refresh"); 4 5 // Prepare this context for refreshing. 6 /*准備要刷新的上下文: 7 設置啟動日期和激活標志,以便執行任意屬性來源的初始化 8 初始化上下文環境中的占位符屬性來演 9 獲取環境信息並校驗必傳參數 10 准備早期的應用程序監聽器 11 准備早期應用監聽事件,一旦多播器可用就將早期的應用事件發布到多播器中*/ 12 prepareRefresh(); 13 14 // Tell the subclass to refresh the internal bean factory. 15 //讓子類刷內置的bean工廠,返回的是ConfigurableListableBeanFactory的子類對象DefaultListableBeanFactory 16 //注意:BeanFactory和ApplicationContext的區別:前者在加載文件時不創建對象,后者在加載文件時就創建好bean對象 17 ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory(); 18 19 // Prepare the bean factory for use in this context. 20 //准備在上下文中使用的bean工廠 21 prepareBeanFactory(beanFactory); 22 23 try { 24 // Allows post-processing of the bean factory in context subclasses. 25 postProcessBeanFactory(beanFactory); 26 27 StartupStep beanPostProcess = this.applicationStartup.start("spring.context.beans.post-process"); 28 // Invoke factory processors registered as beans in the context. 29 //開始調用BeanFactory的后置處理器 30 invokeBeanFactoryPostProcessors(beanFactory); 31 32 // Register bean processors that intercept bean creation. 33 //注冊bean的后置處理器 34 registerBeanPostProcessors(beanFactory); 35 //后置處理器結束 36 beanPostProcess.end(); 37 38 // Initialize message source for this context. 39 //國際化處理,為上下文初始化Message源,即不同語語言的消息體 40 initMessageSource(); 41 42 // Initialize event multicaster for this context. 43 //初始化上下文的事件廣播器 44 initApplicationEventMulticaster(); 45 46 /*Initialize other special beans in specific context subclasses. 47 能夠被覆蓋的模板方法,用來添加特定上下文的更新工作,在特殊bean進行初始化或者單例bean進行實例化時被調用,在該類中是一個空實現 48 三個子類中都是調用UiApplicationContextUtils.initThemeSource(this)方法*/ 49 onRefresh(); 50 51 // Check for listener beans and register them. 52 //在所有注冊的bean中查找Listener bean,注冊到消息廣播器中,即向監聽器發布事件 53 registerListeners(); 54 //-----------------------------------------正餐開始,前方高能預警------------------------------------------- 55 // Instantiate all remaining (non-lazy-init) singletons. 56 //對非延遲初始化的單例進行實例化,一般情況下的單例都會在這里就實例化了,這樣的好處是,在程序啟動過程中就可以及時發現問題 57 finishBeanFactoryInitialization(beanFactory); 58 59 // Last step: publish corresponding event. 60 //最后一步:完成刷新過程,通知生命周期處理器lifecycleProcessor刷新過程 61 finishRefresh(); 62 } catch (BeansException ex) { 63 if (logger.isWarnEnabled()) { 64 logger.warn("Exception encountered during context initialization - " + 65 "cancelling refresh attempt: " + ex); 66 } 67 68 // Destroy already created singletons to avoid dangling resources. 69 //當發生異常時銷毀已經創建的單例 70 destroyBeans(); 71 72 // Reset 'active' flag. 73 //重置active標識為false 74 cancelRefresh(ex); 75 76 // Propagate exception to caller. 77 throw ex; 78 } finally { 79 // Reset common introspection caches in Spring's core, since we 80 // might not ever need metadata for singleton beans anymore... 81 //清空所有的緩存,因為單例bean是在容器啟動時初始化完畢,所以不需要保留它們的元數據信息 82 resetCommonCaches(); 83 contextRefresh.end(); 84 } 85 } 86 }
下一篇:細讀Spring源碼(二)---關於Spring中用到的設計模式
持續更新中........