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