有道無術,術尚可求也!有術無道,止於術!
最近斷更了一段時間,由於公司比較忙,週五的時候在公司作了一個關於Netty的分享,後續會總結一下分享出來!java
最近一段時間發現常常看到不少人,對Spring源碼比較感興趣,平常開發中,不管你作什麼什麼項目,大部分都離不開Spring生態的那一套東西,因此不少人對Spring底層源碼實現很感興趣,可是有些歷來沒有接觸過源碼的開發者,在看Spring源碼的過程當中確實及其難受的,爲何,大部分人看源碼基本都是debug一點一點去看的,最後發現,越追越離譜,越追越深,到最後都追到JDK源碼了,也沒有明白是什麼意思!web
對於學習源碼,個人見解是,先去徹底的熟悉它的用法,想一下若是讓你來實現,你會怎麼實現!有了這些想法以後,再去看源碼去印證你本身的觀點,遠比你本身去死扣源碼快的多。spring
並且,我問過一些讀者還有同事,我發現有不少人,看源碼容易陷入一個誤區,就是剛開始看源碼就死扣着一個細節不放,非得搞懂,我並非說這樣看源碼有什麼不對,可是在沒有對整個框架有一個全局瞭解的狀況下,不要這樣看,你應該先把它的大致框架給搞清楚,在後再分功能一步一步的瞭解每個功能項!這樣作,首先你對整個框架的架構有了一個模糊的認識,再扣細節的途中有時候即便你不知道這個代碼在幹什麼,你也隱約能猜出來,再經過debug 與本身的猜想相互印證,最終達到事半功倍的效果。固然這個建議只針對剛開始看源碼的同窗,若是你看的源碼不少了,那麼你確定又本身的一套學習方法,能夠的話,能夠在留言區或者私聊做者一塊兒交流一下!編程
爲了幫助一些萌新們或者想要了解Spring源碼的小夥伴,我會把Spring的一些大致邏輯分析一下,細節方面,後續做者也會分享,可是今天這一篇文章,只是爲了讓你瞭解整個Spring的骨架!緩存
2、架構圖例
這張圖基本的歸納了Spring初始化bean的整個生命週期,包括你們大概熟悉的一些生命週期的回調,以及AOP或者不少大神都分析過的Spring解決循環依賴的三級緩存,看不懂不要緊,後面做者會帶着源碼一步一步的分析:微信
3、源碼分析
1.前期準備
/**
* spring debug
* @author huangfu
*/
public class SpringDebug {
public static void main(String[] args) {
AnnotationConfigApplicationContext app = new AnnotationConfigApplicationContext(SpringDebugConfig.class);
}
}
上面這一行代碼我估計使用過Spring的人都特別熟悉,若是不熟悉,那我勸你先學會使用,再去深究一些源碼的底層邏輯!架構
下面咱們看一下,他到底是如何一步一步的實例化bean,接管bean,而後執行各類生命週期類的!咱們先不妨猜想一下,spring再讀取這些bean的時候,關於bean的信息必定是存放在了某一個實體上,那麼這個實體是什麼呢?這個類就是BeanDefinition
那麼他存儲了什麼東西呢?咱們看一下它的子類AbstractBeanDefinition
感興趣的小夥伴本身點進去看一下,做者這裏只是爲了讓你們瞭解什麼是BeanDefinition
:app
裏面定義這相似與這樣的屬性值,固然做者作截取了少數屬性,它裏面的屬性遠遠比這多得多,它的目的就是bean實例化的時候,須要的數據不須要再經過本身去反射獲取,而是再Spring初始化的時候所有讀取,須要的時候從這裏面拿就行,瞭解了bd的概念以後,咱們是否疑惑?他讀取以後存放在哪裏呢?答案是存放再beanFactory裏面,因此Spring初始化的時候確定會先實現一個bean工廠!進入到AnnotationConfigApplicationContext
裏面,你會發下並無初始化,在那初始化呢?衆所周知,一個類再初始化的時候會先加載父類的構造函數,因此咱們須要去看一下它的父類GenericApplicationContext
:框架
public GenericApplicationContext() {
//初始化bean的工廠
this.beanFactory = new DefaultListableBeanFactory();
}
果真不出我所料,它再父類裏面建立了bean工廠,工廠有了,咱們繼續回到AnnotationConfigApplicationContext
裏面往下看:發現它調用了一個this(),說明它調用了本身的空構造方法,因此,咱們進入看一下:編輯器
public AnnotationConfigApplicationContext() {
//初始化讀取器
this.reader = new AnnotatedBeanDefinitionReader(this);
//初始化掃描器
this.scanner = new ClassPathBeanDefinitionScanner(this);
}
「至此咱們就能夠看對照上面那幅圖:初始化的時候bean工廠有了」
「而後再本身的空構造方法裏面有初始化了讀取器!」
那咱們繼續回到AnnotationConfigApplicationContext
構造方法裏面:
/**
* 建立一個新的AnnotationConfigApplicationContext,從給定的帶註釋的類派生bean定義
* 並自動刷新上下文。
* @param annotatedClasses one or more annotated classes,
* e.g. {@link Configuration @Configuration} classes
*/
public AnnotationConfigApplicationContext(Class<?>... annotatedClasses) {
//讀取Spring內置的幾個的class文件轉換爲bd 而後初始化bean工廠
this();
//這一步就是將配置類Config進行了註冊並解析bd
register(annotatedClasses);
//這一步是核心,Spring的理解全在這一步,這一步理解了也就能夠說將Spring理解了70%
//內部作一系列的操做如調用bean工廠的後置處理器 實例化類 調用 後置處理器的前置處理 初始化類 調用後置處理器的後置處理 註冊事件監聽等操做
//完成一個類從class文件變爲bean的生命週期
refresh();
}
下一步是調用register
方法,幹什麼呢?試想一下,有時候咱們的自動掃描配置是經過註解@ComponentScan("com.service")
來配置的,這個類通常在哪?對了,通常實在配置類中的!
@Configuration
@ComponentScan("com.service")
public class SpringDebugConfig {}
爲了可以知道,咱們要掃描那些包下的類,咱們就必須先去解析配置類的BeanDefinition
,這樣才能獲取後續我們要解析的包,固然這個方法不光解析了掃描的包,還解析了其餘東西,本文不作講解!
2.核心功能
好了,再往下走咱們就知道了咱們即將要掃描那些包下的類,讓他變成bean,那麼咱們繼續向下走,走到refresh();
這個方法不得了他是整個Springbean初始化的核心方法,瞭解了它也就可以瞭解Spring的實例化,回調等一些列的問題,咱們進去看看:
進來以後,咱們一個方法一個方法的分析作了什麼功能,首先是:
1). prepareRefresh();
❝這裏是作刷新bean工廠前的一系列賦值操做,主要是爲前面建立的Spring工廠不少的屬性都是空的,這個方式是爲他作一些列的初始化值的操做!
❞
2). obtainFreshBeanFactory()
❝告訴子類刷新內部bean工廠 檢測bean工廠是否存在 判斷當前的bean工廠是否只刷新過一次,屢次報錯,返回當前使用的bean工廠,當該步驟爲xml時 會新建一個新的工廠並返回
❞
3). prepareBeanFactory(beanFactory);
❝這裏是初始化Spring的bean容器,向beanFactory內部註冊一些本身自己內置的Bean後置處理器也就是一般說的BeanPostProcessor,這個方法其實也是再初始化工廠!
❞
4). postProcessBeanFactory(beanFactory);
❝容許在上下文子類中對bean工廠進行後處理,做用是在BeanFactory準備工做完成後作一些定製化的處理! 可是注意,你點進去是空方法,空方法覺得着什麼?意味着Spring的開發者但願調用者自定義擴展時使用!
❞
5). invokeBeanFactoryPostProcessors(beanFactory);
❝其實相信看名字,大部分讀者都可以猜出,他的目的是掃描非配置類的bd註冊到工廠裏面,掃描完成以後,開始執行全部的
❞BeanFactoryPostProcessors
,這裏出現了第一個擴展點,自定義實現BeanFactoryPostProcessors
的時候,他的回調時機是在Spring讀取了所有的BeanDefinition
以後調用的,具體的使用方法讀者自行百度!
6). registerBeanPostProcessors(beanFactory);
❝這裏是註冊bean的後置處理器 也就是 beanPostProcessor 的實現 還有本身內置的處理器 注意這裏並無調用該處理器,只是將胡處理器註冊進來bean工廠! 不知道你們使用過
❞beanPostProcessor
接口這個擴展點嗎?他就是再這個方法裏面被註冊到Spring工廠裏面的,固然注意一下,他只是註冊進去了,並無執行!記住並無執行!
7). initMessageSource();
❝怎麼說呢,這個方法做者並不許備深究,由於他和本篇文章的意圖相違背,他的目的是作一個國際化操做也就是 i18n的資源初始化
❞
8).initApplicationEventMulticaster();
❝Spring爲咱們提供了對於事件編程的封裝,通常來講事件分爲三個角色,
❞事件廣播器
(發佈事件),事件監聽器
(監聽事件),事件源
(具體的事件信息)三個角色,這個方法的目的就是初始化事件的廣播器!
9). onRefresh();
❝這裏又是一個擴展點,內部的方法爲空,Spring並無實現它,供調用者實現!
❞
10). registerListeners();
❝註冊Spring的事件監聽器,上面已經說過了,這裏是初始化而且註冊事件監聽器
❞
11). finishBeanFactoryInitialization(beanFactory);
❝這個方法是一個重點,他是爲了實例化全部剩餘的(非延遲初始化)單例。咱們所說的bean的實例化,注入,解決循環依賴,回調
❞beanPostProcessor
等操做都是再這裏實現的!
12). finishRefresh();
❝最後一步:發佈相應的事件。Spring內置的事件
❞
至此咱們完成了整個Spring初始化的生命週期骨架,這裏做者並無深究裏面的實現,只是給讀者搭建了一個架子,幫助讀者理清Spring的脈絡,裏面的填充須要讀者本身填充!如今回過頭去看那個圖,是否是就清晰多了?這裏我再把那個圖放出來,省得大家再翻上去!
好了,今天的文章到這裏也就結束了,做者閒暇時間整理了一份資料,你們有興趣能夠領取下!
才疏學淺,若是文章中理解有誤,歡迎大佬們私聊指正!歡迎關注做者的公衆號,一塊兒進步,一塊兒學習!
❤️「轉發」 和 「在看」 ,是對我最大的支持❤️
本文分享自微信公衆號 - JAVA程序狗(javacxg)。
若有侵權,請聯繫 support@oschina.cn 刪除。
本文參與「OSC源創計劃」,歡迎正在閱讀的你也加入,一塊兒分享。