在Java領域一段時間,原始碼成為大家必學必會必懂的內容。
原始碼直接從AbstractBeanFactory的getBean(String name)開始。
從原始碼可以看出,getBean的主要流程為:
轉換beanName從快取中獲取例項如果例項不為空,且args=null,呼叫getObjectForBeanInstance方法,按照name規則返回相應的bean例項如果上面的條件不成立,則到父容器中查詢beanName對應的bean例項,存在則直接返回如果父容器不存在,合併BeanDefinition處理bean的depends-on依賴,如果存在依賴,則先對依賴建立例項物件建立並對bean進行快取呼叫getObjectForBeanInstance方法,按照name的規則返回相應的bean例項按需轉換bean的型別,返回轉換後的bean型別流程圖為:
2 beanName轉換在獲取bean例項之前,Spring第一件要做的事情是對引數name進行轉換。轉換的目的主要是為了解決兩個問題,第一個是處理以字元&開頭的name,防止BeanFactory無法找到與name對應的bean例項。第二個是處理別名問題,Spring不會儲存<別名,bean例項>這種對映,僅會儲存<beanName,bean>。所以,同樣是為了避免BeanFactory找不到name對應的bean的例項,對於別名也要進行轉換。
3 從快取中獲取bean對於單例的bean,spring容器只會例項化一次,後續再次獲取時,可以直接從快取中獲取,無需再次例項化。從快取中獲取bean的方法為getSingleton(String beanName)。
該原始碼中涉及到了三個map快取:
singletonObjects快取,又稱為一級快取,用於存放完全初始化之後的Bean,從該快取中獲取的bean可以直接使用;earlySingletonObjects快取,又稱為二級快取,用於解決迴圈依賴,存放已經例項化但是還沒有填充屬性的beansingletonFactories快取,又稱為三級快取,用於存放bean工廠,bean工廠所產生的的bean是還沒有完全初始化的bean,使用singletonFactories生成的bean會存放在earlySingletonObjects快取中。上面的方法邏輯不是很複雜,這裡簡單總結一下。如下:
先從singletonObjects集合獲取 bean 例項,若不為空,則直接返回若為空,進入建立bean例項階段。先將beanName新增到singletonsCurrentlyInCreation透過getObject方法呼叫createBean方法建立bean例項將beanName從singletonsCurrentlyInCreation集合中移除將<beanName,singletonObject>對映快取到singletonObjects集合中4. 合併父子BeanDefinition在spring中,子類可以繼承父類的Bean的配置資訊,也可以覆蓋或者重寫父類的配置資訊。如果大家在程式執行期間,檢視子bean的BeanDefinition,可以看到父類的所有配置資訊在bean的BeanDefinition中全部都存在,實現的原始碼如下:
5 從FactoryBean中獲取bean例項getObjectForBeanInstance 及它所呼叫的方法主要做了如下幾件事情:檢測引數beanInstance的型別,如果是非FactoryBean型別的bean,直接返回檢測FactoryBean實現類是否單例型別,針對單例和非單例型別進行不同處理對於單例FactoryBean,先從快取裡獲取FactoryBean生成的例項若快取未命中,則呼叫FactoryBean.getObject()方法生成例項,並放入快取中對於非單例的FactoryBean,每次直接建立新的例項即可,無需快取如果shouldPostProcess=true,不管是單例還是非單例FactoryBean生成的例項,都要進行後置處理參考文件: 田小波部落格 :http://www.tianxiaobo.com/2018/06/01/Spring-IOC-容器原始碼分析-獲取單例-bean/
最新評論