1.IOC容器的依賴注入
SPRing中,依賴注入是在用戶第一次向IOC容器索要Bean時觸發的(通過getBean方法)。
在BeanFactory中我們看到getBean(String…)函數,它的具體實現在AbstractBeanFactory中:
可以看到具體的注入過程轉移到doGetBean(String…)中,在這個方法中,它首先從緩存中取,如果單件模式的bean已經被創建,則這種bean請求不需要重復的創建,調用
跟蹤進入getObjectForBeanInstance(…,null),可以知道因為最后的RootBeanDefinition參數是null,所以執行的是:
而getCachedObjectForFactoryBean(beanName)中實現,其實現很簡單,就是在緩存的bean map中查找bean返回。
繼續回到doGetBean(String…)方法中:
- //取當前bean的所有依賴bean,這樣就會觸發getBean的遞歸調用,直至取到一個沒有任何依賴的bean為止
- String[] dependsOn = mbd.getDependsOn();
- if (dependsOn != null) {
- for (String dependsOnBean : dependsOn) {
- getBean(dependsOnBean);
- //注冊依賴的bean實例,具體實現過程在DefaultSingletonBeanRegistry中實現,其實就是將依賴的bean添加到依賴的hashmap中
- registerDependentBean(dependsOnBean, beanName);
- }
- }
- //通過調用createBean來,創建單例bean的實例
- if (mbd.isSingleton()) {
- sharedInstance = getSingleton(beanName, new ObjectFactory() {
- public Object getObject() throws BeansException {
- try {
- return createBean(beanName, mbd, args);
- }
- catch (BeansException ex) {
- destroySingleton(beanName);
- throw ex;
- }
- }
- });
- bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
- }
- //同樣調用createBean創建prototype的bean實例
- else if (mbd.isPrototype()) {
- // It's a prototype -> create a new instance.
- Object prototypeInstance = null;
- try {
- beforePrototypeCreation(beanName);
- prototypeInstance = createBean(beanName, mbd, args);
- }
- finally {
- afterPrototypeCreation(beanName);
- }
- bean=getObjectForBeanInstance(prototypeInstance,name, beanName, mbd);
- }
繼續看createBean(…),可以看到在AbstractBeanFactory中它只是個抽象類,具體的實現交給其子類(又見模板模式),進入子類AbstractAutowireCapableBeanFactory中看createBean的具體實現:
其具體的實現轉到doCreateBean(String…),這里我們看到與依賴注入關系比較密切的方法有createBeanInstance和populateBean。
在createBeanInstance中生成了Bean所包含的Java對象,這個對象的生成有很多不同的方式,可以通過工廠方法生成,也可以通過容器的autowire特性生成,生成的方式由相關聯的BeanDefinition來指定,進入createBeanInstance方法,有:
上面是其中的兩個實例化方法,上面的是在BeanDefinition的FactoryMethod存在的情況下,使用工廠方法對bean進行實例化。下面一個是使用默認的構造函數對bean進行實例化。我們進入instantiateBean(beanName,mbd),可以看到有:
因為getInstantiationStrategy()返回的默認的實例化策略,而默認的實例化策略是CglibSubclassingInstantiationStrategy,也即用cglib來對bean進行實例化。CGLIB是一個常用的字節碼生成器的類庫,它提供了一系列的API來提供Java的字節碼生成和轉換功能。
我們再次回到doCreateBean()中的populateBean方法,看看在實例化Bean對象生成的基礎上,spring怎樣把這些bean對象的依賴關系設置好,完成整個依賴注入過程。在populateBean中,先是取得在BeanDefinition中設置的property值,這些property來自對BeanDefinition的解析,接著便開始進行依賴注入過程:
最后在通過applyPropertyValues對屬性進行注入:
接著我們到applyPropertyValues中去看具體的對屬性進行解析然后注入的過程,在其中會調用BeanDefinitionValueResolver對BeanDefinition進行解析,
接著為解析值創建一個拷貝,拷貝的數據將會被注入到bean中,它會先對PropertyValue判斷,如果其沒有經過轉換則會調用resolveValueIfNecessary進行解析,然后注入到property中。下面到BeanDefinitionValueResolver中去看一下解析過程的實現,在函數resolveValueIfNecessary中包含了所有對注入類型的處理,以RuntimeBeanReference(其是在對BeanDefinition進行解析時生成的數據對象)為例:
在上面的實現中,無論是到雙親的IOC容器中去取,還是在當前IOC容器中取,都會觸發一個getBean的過程,這就觸發了相應的依賴注入的發生。
這就完成了resolve的過程,為依賴注入準備好了條件。但真正的把Bean對象設置到它所依賴的另一個Bean的屬性中去的地方是在BeanWrapper的setPropertyValues中(在分析populateBean的時候有提到),其中處理的屬性是各種各樣的。setPropertyValues的具體實現是在BeanWrapper的子類BeanWrapperImpl中:
在doCreateBean中執行完populateBean,完成Bean的生成和依賴注入以后,開始對Bean進行初始化,這個初始化過程包含了對后置處理器的postProcessBeforeInitializtion回調,具體實現在initializeBean方法中:
新聞熱點
疑難解答