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進去看看。