天天看點

spring bean加載--從緩存中擷取bean

标簽:spring源碼學習

入口方法:getsingleton,在

真正的實作:

spring單例在同一個spring容器中隻建立一次,之後在擷取bean的時候,會首先嘗試從緩存加載bean,首先從singletonobjects中擷取,singletonobjects中存儲的是beanname->bean instance, 如果緩存為空,但該bean正在建立過程中(issingletoncurrentlyincreation)則嘗試從singletonfactories中擷取。這是因為spring建立單例bean的時候,存在循環依賴的問題。比如建立bean a的時候發現bean a引用了bean b,此時會去建立bean b,但又發現bean b引用了bean c,是以此時會去建立bean c,在建立bean c的過程中發現bean c引用bean a。這三個bean就形成了一個環。為了解決循環依賴的問題,spring采取了一種将建立的bean執行個體提早暴露加入到緩存中,一旦下一個bean建立的時候需要依賴上個bean,則直接使用objectfactory來擷取bean。提前暴露bean執行個體到緩存的時機是在bean執行個體建立(調用構造方法)之後,初始化bean執行個體(屬性注入)之前。具體在abstractautowirecapablebeanfactory類的

方法中。在該方法中調用了defaultsingletonbeanregistry類的

将允許提前暴露的單例bean提前加入singletonfactories中,這樣就可以在建立依賴的時候避免循環依賴問題。

在從singletonfactories擷取bean後,會将其存儲到earlysingletonobjects中,然後從singletonfactories移除該bean,之後在要擷取該bean就直接從earlysingletonobjects擷取。這是因為從singletonfactories擷取bean過程中需要調用singletonfactory.getobject(),這裡還有一些操作,這樣可以進一步提升性能。緩存思想用的很多。在java裡面緩存大多都是指一個map結構,我想這應該是map的get和put操作都是o(1),适合用作緩存。

spring bean加載相關的緩存有以下這些:

singletonobjects和earlysingletonobjects的差別主要在于earlysingletonobjects是為了解決循環依賴設定的,儲存的是提前暴露的bean name –> bean instance,而singletonobjects存儲的是完全執行個體化的bean name –> bean instance。

最後附上我看源碼自己寫的例子:首先定義了三個bean,

測試方法:

testa提前暴露在singletonfactories的快照

spring bean加載--從緩存中擷取bean

當testc引用了testa,此時直接從singletonfactories擷取objectfactory,調用其getobject()方法擷取提前暴露的testa,快照如下

spring bean加載--從緩存中擷取bean
spring bean加載--從緩存中擷取bean