SpringIoC
是什么?
官方文檔的解釋是:IoC也稱為依賴注入(DI)。在此過程中,對象僅通過構造函數參數,工廠方法的參數或在構造或從工廠方法返回后在對象實例上設置的屬性來定義其依賴項(即,與它們一起使用的其他對象) 。然后,容器在創建bean時注入那些依賴項。從本質上講,此過程是通過使用類的直接構造或諸如服務定位器模式之類的機制來控制其依賴關系的實例化或位置的Bean本身的逆過程(因此,其名稱為Control Inversion)。
簡單來說:就是我們將一個個的bean對象交給IoC去管理,他會幫助我們去創建對象實例、填充屬性、初始化、添加監聽器等過程。
類圖
我們以常用的ClassPathXmlApplicationContext為例
大致過程
首先,一個IoC容器應創建一個工廠(DefaultListableBeanFactory),可以使我們讀取的資源文件可以存放。
然后,將配置文件通過一個規范(BeanDefinitionReader)加載出來。
接着,是bean對象實例化之前的一些准備(初始化啊、事件處理器、注冊組件等);例如上圖中的BeanFactoryPostProcessor、多播器等。
重要的地方來了,創建一個個的非懶加載的成品Bean對象(finishBeanFactoryInitialization方法)。
最后,是一些事件的發布、緩存、銷毀等。
源碼分析
從ClassPathXmlApplicationContext開始分析。在它的構造方法中,我們可以看見調用了父類(AbstractApplicationContext類)的構造方法、設置配置文件的加載路徑以及核心方法refresh()方法。
父類AbstractApplicationContext的構造方法
setConfigLocations()方法
接下來,我們進入核心方法refresh()。
我們重點看序號2和序號11,其他有興趣可以自己點進去看看。
obtainFreshBeanFactory()方法
跟進refreshBeanFactory()方法,在AbstractRefreshableApplicationContext類中可以找到refreshBeanFactory()這個方法
createBeanFactory()方法中
loadBeanDefinitions()方法,也是委派給子類去實現。
我們進去子類AbstractXmlApplicationContext類的loadBeanDefinition()方法。在這里進行了配置文件讀取規范的定義,我們繼續跟進loadBeanDefinitions()方法。
loadBeanDefinitions()方法。傳入的可能是個String[]或者Resource[]類型。但是大致流程都差不多:String[]->String->Resource[]->Resource->Document->BeanDefinition。這里就不過多深入了,感興趣可以照這個流程看下去。
資源文件加載完成后,我們的BeanFactory差不多就創建好了。接着,我們到IoC最重要的過程,Bean對象(不是懶加載的)的實例化和初始化。這里為什么將實例化和初始化分開說呢,是想更好的幫助理解Bean對象的創建過程。其實Spring中更加的細分了一下,分成了實例化(createBeanInstance()方法)、填充屬性(populateBean()方法)和初始化(initializeBean()方法)。
實例化:在堆中開辟了一塊空間。屬性都是系統默認值。
初始化:給屬性完成具體的賦值操作,調用具體的初始化方法。
好了,我們進入finishBeanFactoryInitialization()方法,里面你會看到一些對beanFactory的屬性設置,其中重點的是preInstantiateSingletons()方,點進去,它會調用DefaultListableBeanFactory的preInstantiateSingletons()方法。
我們可以看到getBean()方法,這里就是准備開始進行bean對象的創建了。點進去,我們可以看真正執行的是doGetBean()方法
doGetBean()方法,就是根據不同的Bean采用不同的創建策略。
1. 如果Bean是單例的,則在容器創建之前先從緩存中查找,確保整個容器只存在一個實例對象
2. 如果Bean是原型模式的,則容器每次都會創建一個新的實例對象
3. 指定了Bean的生命周期
我們進入createBean(),發現還有一個doCreateBean方法(),終於,我們到了真正創建Bean對象的方法。點進去。
我們發現我們終於找到了之前所說的那三個方法了,創建、填充和初始化。
createBeanInstance()方法返回的是一個BeanWrapper,bean的封裝類。
populateBean()則是將bean的一些屬性字段進行解析、填充。
在initializeBean()中
到此,我們一開始的流程圖所有的地方差不多都完成了。其中有些細節方面沒點進去看看,主要是大致了解IoC的過程。可以自行debug進去看看。