教育行業(yè)A股IPO第一股(股票代碼 003032)

全國咨詢/投訴熱線:400-618-4000

Spring Bean的生命周期分為幾個階段?【Java高頻面試題】

更新時間:2023年04月06日15時45分 來源:傳智教育 瀏覽次數(shù):

好口碑IT培訓(xùn)

Spring Bean的生命周期是從Bean 實(shí)例化之后,即通過反射創(chuàng)建出對象之后,到Bean成為一個完整對象,最終存儲到單例池中,這個過程被稱為Spring Bean的生命周期。Spring Bean的生命周期大體上分為三個階段:

Bean的實(shí)例化階段:Spring框架會取出BeanDefinition的信息進(jìn)行判斷當(dāng)前Bean的范圍是否是singleton的,是否不是延遲加載的,是否不是FactoryBean等,最終將一個普通的singleton的Bean通過反射進(jìn)行實(shí)例化;

Bean的初始化階段:Bean創(chuàng)建之后還僅僅是個"半成品",還需要對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)引用問題都是在這個階段體現(xiàn)的;

Bean的完成階段:經(jīng)過初始化階段,Bean就成為了一個完整的Spring Bean,被存儲到單例池singletonObjects中去了,即完成了Spring Bean的整個生命周期。

由于Bean的初始化階段的步驟比較復(fù)雜,所以著重研究Bean的初始化階段Spring Bean的初始化過程涉及如下幾個過程:

? Bean實(shí)例的屬性填充

? Aware接口屬性注入

? BeanPostProcessor的before()方法回調(diào)

? InitializingBean接口的初始化方法回調(diào)

? 自定義初始化方法init回調(diào)

? BeanPostProcessor的after()方法回調(diào)

PS:通過代碼驗(yàn)證上述初始化順序… …

Bean實(shí)例屬性填充

BeanDefinition中有對當(dāng)前Bean實(shí)體的注入信息通過屬性propertyValues進(jìn)行了存儲,例如UserService的屬性信息如下:

Bean實(shí)例屬性填充

Spring在進(jìn)行屬性注入時,會分為如下幾種情況:

注入普通屬性,String、int或存儲基本類型的集合時,直接通過set方法的反射設(shè)置進(jìn)去;

注入單向?qū)ο笠脤傩詴r,從容器中g(shù)etBean獲取后通過set方法反射設(shè)置進(jìn)去,如果容器中沒有,則先創(chuàng)建被注入對象Bean實(shí)例(完成整個生命周期)后,在進(jìn)行注入操作;

注入雙向?qū)ο笠脤傩詴r,就比較復(fù)雜了,涉及了循環(huán)引用(循環(huán)依賴)問題,下面會詳細(xì)闡述解決方案。

PS:通過代碼驗(yàn)證上述第二第三種屬性填充… …

多個實(shí)體之間相互依賴并形成閉環(huán)的情況就叫做"循環(huán)依賴",也叫做"循環(huán)引用"例如下圖,beanA和beanA的依賴關(guān)系。

循環(huá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í)例化與初始化的順序如下:

初始化與實(shí)例化的順序

Spring提供了三級緩存存儲完整Bean實(shí)例和半成品Bean實(shí)例,用于解決循環(huán)引用問題。 在DefaultListableBeanFactory的上四級父類DefaultSingletonBeanRegistry中提供如下三個Map:

public class DefaultSingletonBeanRegistry ... {
    //1、最終存儲單例Bean成品的容器,即實(shí)例化和初始化都完成的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實(shí)例化對象,但尚未初始化,將UserService存儲到三級緩存;

UserService屬性注入,需要UserDao,從緩存中獲取,沒有UserDao;

UserDao實(shí)例化對象,但尚未初始化,將UserDao存儲到到三級緩存;

UserDao屬性注入,需要UserService,從三級緩存獲取UserService,UserService從三級緩存移入二級緩存;

UserDao執(zhí)行其他生命周期過程,最終成為一個完成Bean,存儲到一級緩存,刪除二三級緩存;

UserService注入UserDao;

UserService執(zhí)行其他生命周期過程,最終成為一個完成Bean,存儲到一級緩存,刪除二三級緩存。

常用的Aware接口

Aware接口是一種框架輔助屬性注入的一種思想,其他框架中也可以看到類似的接口。框架具備高度封裝性,我們接觸到的一般都是業(yè)務(wù)代碼,一個底層功能API不能輕易的獲取到,但是這不意味著永遠(yuǎn)用不到這些對象,如果用到了。
常用Aware接口

0 分享到:
和我們在線交談!