1. 程式人生 > >SpringIOC 例項化Bean的流程

SpringIOC 例項化Bean的流程

http://www.voidcn.com/blog/qq_16681169/article/p-5050775.html

在網上看一個Bean例項化過程的圖,寫的非常棒。轉過來後,在最後面加了原始碼的入口,有興趣的朋友可通過入口看看原始碼

IoC容器的初始化就是含有BeanDefinition資訊的Resource的定位、載入、解析、註冊四個過程,最終我們配置的bean,以beanDefinition的資料結構存在於IoC容器即記憶體中。這裡並不涉及bean的依賴注入,只是bean定義的載入。但有例外,在使用Ioc容器時有一個預例項化的配置,即bean定義中的設定了lazyinit屬性,那麼這個bean在Ioc容器初始化時就預先載入,不需要等到Ioc整個初始化後,第一次getBean時才會觸發。其中refresh()啟動對Ioc容器的初始化。
第一過程是Resource定位過程。這個Resource定位指的是BeanDefinition的資源定位,它由ResourceLoader通過統一的Resource介面來完成,這個Resource對各種形式的BeanDefinition的使用提供了統一介面。對於這些BeanDefinition的存在形式,相信大家都不會感到陌生。比如說,在檔案系統中的Bean定義資訊可以使用FileSystemResource來進行抽象;在類路徑中可以使用前面提到的ClassPathResource來使用,等等。這個過程類似於容器尋找資料的過程,就像用水桶裝水先要把水找到一樣。
第二個關鍵的部分是BeanDefinition的載入,該載入過程把使用者定義好的Bean表示成IoC容器內部的資料結構,而這個容器內部的資料結構就是BeanDefinition,下面可以看到這個資料結構的詳細定義。總地說來,這個BeanDefinition實際上就是POJO物件在IoC容器中的抽象,這個BeanDefinition定義了一系列的資料來使得IoC容器能夠方便地對POJO物件也就是Spring的Bean進行管理。即BeanDefinition就是Spring的領域物件。下面我們會對這個載入的過程進行詳細的分析,便於大家對整個過程有比較清楚的瞭解。

第三個過程是向IoC容器註冊這些BeanDefinition的過程。這個過程是通過呼叫BeanDefinitionRegistry介面的實現來完成的,這個註冊過程把載入過程中解析得到的BeanDefinition向IoC容器進行註冊。可以看到,在IoC容器內部將BeanDefinition注入到一個HashMap中去,Ioc容器是通過這個HashMap來持有這些BeanDefinition資料的。

Sping IOC例項化流程:
1.ResourceLoader從儲存介質中載入Spring配置資訊,並使用Resource表示這個配置檔案的資源;

2.BeanDefinitionReader讀取Resource所指向的配置檔案資源,然後解析配置檔案。配置檔案中的每一個解析成一個BeanDefinition物件,並儲存到BeanDefinitionRegistry中;

3.容器掃描BeanDefinitionRegistry中的BeanDefinition,使用Java的反射機制自動識別出Bean工廠處理器(實現BeanFactoryPostProcessor介面)的Bean,然後呼叫這些Bean工廠後處理器對BeanDefinitionRegistry中的BeanDefinition進行加工處理;

4.Spring容器從BeanDefinitionRegistry中取出加工後的BeanDefinition,並呼叫InstantiationStrategy著手進行Bean例項化工作;

5.在例項化Bean時,Spring容器使用BeanWrapper對Bean進行封裝,BeanWrapper提供了很多以Java反射機制操作Bean的方法,它將結合該Bean的BeanDefinition以及容器中屬性編輯器,完成Bean屬性的設定工作;

6.利用容器中註冊的Bean後處理器(實現BeanPostProcessor介面的Bean)對已經完成屬性設定工作的Bean進行後續加工,直接裝配出一個準備就緒的Bean。

如果想要看相關的原始碼,可以按下面的過程來看:

入口是AbstractApplicationContext#refresh()方法,這個方法是對BeanFactory的各種操作,定位、載入、解析,註冊的過程的入口都在這個方法裡。定位、載入的入口是obtainFreshBeanFactory()方法,而解析、註冊的入口是finishBeanFactoryInitialization()方法。

1,關於BeanDefinition定位、載入:

當進入obtainFreshBeanFactory()方法後,再進入refreshBeanFactory()方法裡(這個方法的其中一個實現是AbstractRefreshableApplicationContext),可以看到loadBeanDefinitions()方法,整個過程就是這個方法中進行的。

2,關於BeanDefinition解析,註冊:

當進入finishBeanFactoryInitialization()方法後,再進入beanFactory.preInstantiateSingletons()方法裡面(這個方法的實現是在DefaultListableBeanFactory裡面),然後再找到getBean(beanName)方法(這個方法裡的實現是在AbstractBeanFactory裡面),在這個方法裡面再進入doGetBean()方法裡,Bean的解析,註冊過程全是在這個方法裡面進行的。