更新時(shí)間:2023年04月06日15時(shí)45分 來源:傳智教育 瀏覽次數(shù):
Spring Bean的生命周期是從Bean 實(shí)例化之后,即通過反射創(chuàng)建出對(duì)象之后,到Bean成為一個(gè)完整對(duì)象,最終存儲(chǔ)到單例池中,這個(gè)過程被稱為Spring Bean的生命周期。Spring Bean的生命周期大體上分為三個(gè)階段:
Bean的實(shí)例化階段:Spring框架會(huì)取出BeanDefinition的信息進(jìn)行判斷當(dāng)前Bean的范圍是否是singleton的,是否不是延遲加載的,是否不是FactoryBean等,最終將一個(gè)普通的singleton的Bean通過反射進(jìn)行實(shí)例化;
Bean的初始化階段:Bean創(chuàng)建之后還僅僅是個(gè)"半成品",還需要對(duì)Bean實(shí)例的屬性進(jìn)行填充、執(zhí)行一些Aware接口方法、執(zhí)行BeanPostProcessor方法、執(zhí)行InitializingBean接口的初始化方法、執(zhí)行自定義初始化init方法等。該階段是Spring最具技術(shù)含量和復(fù)雜度的階段,Aop增強(qiáng)功能,后面要學(xué)習(xí)的Spring的注解功能等、spring高頻面試題Bean的循環(huán)引用問題都是在這個(gè)階段體現(xiàn)的;
Bean的完成階段:經(jīng)過初始化階段,Bean就成為了一個(gè)完整的Spring Bean,被存儲(chǔ)到單例池singletonObjects中去了,即完成了Spring Bean的整個(gè)生命周期。
由于Bean的初始化階段的步驟比較復(fù)雜,所以著重研究Bean的初始化階段Spring Bean的初始化過程涉及如下幾個(gè)過程:
? Bean實(shí)例的屬性填充
? Aware接口屬性注入
? BeanPostProcessor的before()方法回調(diào)
? InitializingBean接口的初始化方法回調(diào)
? 自定義初始化方法init回調(diào)
? BeanPostProcessor的after()方法回調(diào)
PS:通過代碼驗(yàn)證上述初始化順序… …
Bean實(shí)例屬性填充
BeanDefinition中有對(duì)當(dāng)前Bean實(shí)體的注入信息通過屬性propertyValues進(jìn)行了存儲(chǔ),例如UserService的屬性信息如下:
Spring在進(jìn)行屬性注入時(shí),會(huì)分為如下幾種情況:
注入普通屬性,String、int或存儲(chǔ)基本類型的集合時(shí),直接通過set方法的反射設(shè)置進(jìn)去;
注入單向?qū)ο笠脤傩詴r(shí),從容器中g(shù)etBean獲取后通過set方法反射設(shè)置進(jìn)去,如果容器中沒有,則先創(chuàng)建被注入對(duì)象Bean實(shí)例(完成整個(gè)生命周期)后,在進(jìn)行注入操作;
注入雙向?qū)ο笠脤傩詴r(shí),就比較復(fù)雜了,涉及了循環(huán)引用(循環(huán)依賴)問題,下面會(huì)詳細(xì)闡述解決方案。
PS:通過代碼驗(yàn)證上述第二第三種屬性填充… …
多個(gè)實(shí)體之間相互依賴并形成閉環(huán)的情況就叫做"循環(huán)依賴",也叫做"循環(huán)引用"例如下圖,beanA和beanA的依賴關(guān)系。
public class UserServiceImpl implements UserService{ public void setUserDao(UserDao userDao) {} } public class UserDaoImpl implements UserDao{ public void setUserService(UserService userService){} } <bean id="userService" class="com.itheima.service.impl.UserServiceImpl"> <property name="userDao" ref="userDao"/> </bean> <bean id="userDao" class="com.itheima.dao.impl.UserDaoImpl"> <property name="userService" ref="userService"/> </bean>
代碼驗(yàn)證后,分析出UserService與UserDao實(shí)例化與初始化的順序如下:
Spring提供了三級(jí)緩存存儲(chǔ)完整Bean實(shí)例和半成品Bean實(shí)例,用于解決循環(huán)引用問題。 在DefaultListableBeanFactory的上四級(jí)父類DefaultSingletonBeanRegistry中提供如下三個(gè)Map:
public class DefaultSingletonBeanRegistry ... { //1、最終存儲(chǔ)單例Bean成品的容器,即實(shí)例化和初始化都完成的Bean,稱之為"一級(jí)緩存" Map<String, Object> singletonObjects = new ConcurrentHashMap(256); //2、早期Bean單例池,緩存半成品對(duì)象,且當(dāng)前對(duì)象已經(jīng)被其他對(duì)象引用了,稱之為"二級(jí)緩存" Map<String, Object> earlySingletonObjects = new ConcurrentHashMap(16); //3、單例Bean的工廠池,緩存半成品對(duì)象,對(duì)象未被引用,使用時(shí)在通過工廠創(chuàng)建Bean,稱之為"三級(jí)緩存" Map<String, ObjectFactory<?>> singletonFactories = new HashMap(16); }
UserService和UserDao循環(huán)依賴的過程結(jié)合上述三級(jí)緩存描述:
UserService實(shí)例化對(duì)象,但尚未初始化,將UserService存儲(chǔ)到三級(jí)緩存;
UserService屬性注入,需要UserDao,從緩存中獲取,沒有UserDao;
UserDao實(shí)例化對(duì)象,但尚未初始化,將UserDao存儲(chǔ)到到三級(jí)緩存;
UserDao屬性注入,需要UserService,從三級(jí)緩存獲取UserService,UserService從三級(jí)緩存移入二級(jí)緩存;
UserDao執(zhí)行其他生命周期過程,最終成為一個(gè)完成Bean,存儲(chǔ)到一級(jí)緩存,刪除二三級(jí)緩存;
UserService注入U(xiǎn)serDao;
UserService執(zhí)行其他生命周期過程,最終成為一個(gè)完成Bean,存儲(chǔ)到一級(jí)緩存,刪除二三級(jí)緩存。
常用的Aware接口
Aware接口是一種框架輔助屬性注入的一種思想,其他框架中也可以看到類似的接口??蚣芫邆涓叨确庋b性,我們接觸到的一般都是業(yè)務(wù)代碼,一個(gè)底層功能API不能輕易的獲取到,但是這不意味著永遠(yuǎn)用不到這些對(duì)象,如果用到了。
北京校區(qū)