<code>/**<br> * spring debug<br> * @author huangfu<br> */<br>public class SpringDebug {<br>public static void main(String[] args) {<br> AnnotationConfigApplicationContext app = new AnnotationConfigApplicationContext(SpringDebugConfig.class);<br> }<br>}<br></code>
上面這一行程式碼我估計使用過Spring的人都特別熟悉,如果不熟悉,那我勸你先學會使用,再去深究一些源碼的底層邏輯!
下面我們來看看,他究竟是如何一步一步的實例化bean,接管bean,然後執行各種生命週期類別的!我們先不妨猜測一下,spring再讀取這些bean的時候,關於bean的資訊一定是存放在了某一個實體上,那麼這個實體是什麼呢?這個類別就是BeanDefinition
那他儲存了什麼東西呢?我們來看看它的子類別AbstractBeanDefinition
#裡面定義這類似與這樣的屬性值,當然作者做截斷了少數屬性,它裡面的屬性遠遠比這多得多,它的目的就是bean實例化的時候,需要的資料不需要再透過自己去反射獲取,而是再Spring初始化的時候全部讀取,需要的時候從這裡面拿就行,了解了bd的概念之後,我們是否疑惑?他讀取之後存放在哪裡呢?答案是存放再beanFactory裡面,所以Spring初始化的時候一定會先實現一個bean工廠!進入AnnotationConfigApplicationContext
裡面,你會發下來並沒有初始化,在那初始化呢?眾所周知,一個類別再初始化的時候會先載入父類別的建構函數,所以我們需要去看一下它的父類別GenericApplicationContext
:
<code>public GenericApplicationContext() {<br> //初始化bean的工厂<br> this.beanFactory = new DefaultListableBeanFactory();<br>}</code>
果然不出我所料,它再父類別裡面創建了bean工廠,工廠有了,我們繼續回到AnnotationConfigApplicationContext
裡面往下看:發現它調用了一個this(),說明它調用了自己的空構造方法,所以,我們進入看一下:
<code>public AnnotationConfigApplicationContext() {<br> //初始化读取器<br> this.reader = new AnnotatedBeanDefinitionReader(this);<br> //初始化扫描器<br> this.scanner = new ClassPathBeanDefinitionScanner(this);<br>}</code>
「至此我們就可以看對照上面那張圖:初始化的時候bean工廠有了」
#「然後再自己的空構造方法裡面有初始化了讀取器!」
那我們繼續回到AnnotationConfigApplicationContext 建構方法裡面:
<code> /**<br> * 创建一个新的AnnotationConfigApplicationContext,从给定的带注释的类派生bean定义<br> * 并自动刷新上下文。<br> * @param annotatedClasses one or more annotated classes,<br> * e.g. {@link Configuration @Configuration} classes<br> */<br>public AnnotationConfigApplicationContext(Class>... annotatedClasses) {<br>//读取Spring内置的几个的class文件转换为bd 然后初始化bean工厂<br>this();<br>//这一步就是将配置类Config进行了注册并解析bd<br> register(annotatedClasses);<br>//这一步是核心,Spring的理解全在这一步,这一步理解了也就可以说将Spring理解了70%<br>//内部做一系列的操作如调用bean工厂的后置处理器 实例化类 调用 后置处理器的前置处理 初始化类 调用后置处理器的后置处理 注册事件监听等操作<br>//完成一个类从class文件变为bean的生命周期<br> refresh();<br> }</code>下一步就是呼叫
register方法,幹嘛呢?試想一下,有時候我們的自動掃描配置是透過註解
@ComponentScan("com.service")來設定的,這個類別一般在哪?對了,一般實在配置類別的!
<code>@Configuration<br>@ComponentScan("com.service")<br>public class SpringDebugConfig {}</code>為了能夠知道,我們要掃描那些包下的類,我們就必須先去解析配置類的
BeanDefinition,這樣才能獲取後續咱們要解析的包,當然這個方法不光解析了掃描的包,還解析了其他東西,本文不做講解!
refresh();這個方法不得了他是整個Springbean初始化的核心方法,了解了它也就能夠了解Spring的實例化,回調等一些列的問題,我們進去看看:
這裡是做刷新bean工廠前的一系列賦值操作,主要是為前面創建的Spring工廠很多的屬性都是空的,這個方式是為他做一些列的初始化值的操作!2 ). obtainFreshBeanFactory()❝❞
告訴子類別刷新內部bean工廠 檢測bean工廠是否存在判斷當前的bean工廠是否只刷新過一次,多次報錯,返回當前使用的bean工廠,當步驟為xml時會新建一個新的工廠並返回3). prepareBeanFactory(beanFactory);❝ # beanFactory內部註冊一些自己本身內建的Bean後置處理器也就是通常說的BeanPostProcessor,這個方法其實也是再初始化工廠!❞
❞
❝允許在情境子類別中對bean進行後處理,準備完成工作後準備完成工作的處理! 但要注意,你點進去是空方法,空方法以為什麼?意味著Spring的開發者希望呼叫者自訂擴充時使用!
❞
#❝其實有掃描名字,讀者大多能猜出非配置bd註冊到工廠裡面,掃描完成之後,開始執行所有的
❞BeanFactoryPostProcessors
,這裡出現了第一個擴展點,自定義實現BeanFactoryPostProcessors
的時候,他的回調時機是在Spring讀取了全部的BeanDefinition
之後呼叫的,具體的使用方法讀者自行百度!
❝這裡是註冊bean的後置處理器與裝置為原始碼這裡並沒有呼叫該處理器,只是將胡處理器註冊進來bean工廠! 不知道大家使用過
❞beanPostProcessor
接口這個擴充點嗎?他就是再這個方法裡面被註冊到Spring工廠裡面的,當然注意一下,他只是註冊進去了,並沒有執行!記住並沒有執行!
❝怎麼說呢,這個方法作者並不准備深究,因為他和本篇文章的意圖相違背,他的目的是要做一個國際化作業也就是i18n的資源初始化
❞
❝的封裝,一般來說事件分為三個角色,9). onRefresh();❝事件廣播器
(發布事件),
事件監聽器(監聽事件),
事件來源(具體的事件資訊)三個角色,這個方法的目的就是初始化事件的廣播器!
❞
9).這裡又是一個擴充點,內部的方法,以供呼叫!
❞
❝註冊Spring的事件監聽器,上面已經說過了,這裡是初始化並且註冊事件監聽器
❞
#❝這個方法是重點,祂是為了實例化所有剩餘的(非延遲實例化所有剩餘的(非延遲實例化)單例。我們所說的bean的實例化,注入,解決循環依賴,回呼
❞beanPostProcessor
等操作都是再這裡實現的!
❝#最後一步:發佈對應的事件。 Spring內建的事件
❞
以上是java中Spring源碼分析的詳細內容。更多資訊請關注PHP中文網其他相關文章!