《面試1v1》SpringBean生命周期
我是 javapub,一名 Markdown 程序員從?????,八股文種子選手。
面試官:小伙子,聽說你對 Spring Bean 生命周期比較熟悉,我們聊聊吧。Spring Bean 都有哪些生命周期階段?
候選人: Spring Bean 的生命周期可以分為 5 個階段:
- 實例化(Instantiation):Spring 使用 BeanDefinition 中的信息實例化 Bean。
- 屬性賦值(Dependency injection):Spring 將 BeanDefinition 中配置的屬性值注入到 Bean 中。
- 初始化前階段(Post-Construct):如果 Bean 實現(xiàn)了 InitializingBean 接口,會調(diào)用 afterPropertiesSet() 方法。
- 初始化階段(Initialization):如果在 BeanDefinition 中配置了 init-method,會調(diào)用該方法。
- 銷毀階段(Destruction):如果 Bean 實現(xiàn)了 DisposableBean 接口,會調(diào)用 destroy() 方法。如果配置了 destroy-method,會調(diào)用該方法。
面試官:聰明!初始化方法有哪些?在源碼層面,Spring 是如何調(diào)用這些方法的?
候選人: Spring Bean 提供了 3 種初始化方法:
- @PostConstruct:這是 JSR-250 注解,Spring 會在 Bean 初始化后自動調(diào)用被此注解標(biāo)注的方法。
- InitializingBean 接口:這個接口只有一個方法 afterPropertiesSet(),Spring 會在 Bean 初始化后調(diào)用該方法。
- 自定義 init-method:在 BeanDefinition 中配置 init-method 屬性,指向 Bean 中的某個方法名,Spring 會在 Bean 初始化后調(diào)用這個方法。
在源碼層面,這些方法的調(diào)用是在 AbstractAutowireCapableBeanFactory 的 initializeBean 方法中實現(xiàn)的:
protected?Object?initializeBean(final?String?beanName,?final?Object?bean,?@Nullable?RootBeanDefinition?mbd)?{
????//?...
????????
????//?1.?處理?PostConstruct?注解
????if?(mbd?==?null?||?!mbd.isExternallyManagedInitMethod("afterPropertiesSet"))?{
????????//?2.?實現(xiàn)了?InitializingBean?接口的?Bean?會調(diào)用?afterPropertiesSet()?方法
????????if?(bean?instanceof?InitializingBean)?{
????????????((InitializingBean)?bean).afterPropertiesSet();
????????}
????}
????//?3.?調(diào)用自定義的?init-method?
????if?(mbd?!=?null?&&?bean.getClass()?!=?NullBean.class)?{
????????String?initMethodName?=?mbd.getInitMethodName();
????????if?(StringUtils.hasLength(initMethodName)?&&?
????????????!(bean?instanceof?InitializingBean?&&?"afterPropertiesSet".equals(initMethodName))?&&
????????????!mbd.isExternallyManagedInitMethod(initMethodName))?{
????????????????Method?initMethod?=?bean.getClass().getMethod(initMethodName);
????????????????initMethod.invoke(bean);
????????}
????}
}
面試官:不錯,你對 Spring Bean 的初始化過程很清楚!那銷毀方法哪些?原理又是什么?
候選人: Spring Bean 提供了 2 種銷毀方法:
- DisposableBean 接口:實現(xiàn)這個接口的 Bean 會調(diào)用 destroy() 方法。
- 自定義 destroy-method:在 BeanDefinition 中配置 destroy-method 屬性,指向 Bean 中的某個方法名,Spring 會在 Bean 銷毀前調(diào)用這個方法。
在源碼層面,這些方法的調(diào)用是在 AbstractAutowireCapableBeanFactory 的 destroyBean 方法中實現(xiàn)的:
protected?void?destroyBean(String?beanName,?@Nullable?DisposableBean?bean)?{
????//?1.?實現(xiàn)了?DisposableBean?接口的?Bean?會調(diào)用?destroy()?方法
????if?(bean?!=?null)?{?
????????bean.destroy();
????}
????//?2.?調(diào)用自定義的?destroy-method
????String?destroyMethodName?=?getDestroyMethodName(beanName);
????if?(destroyMethodName?!=?null)?{
????????Method?destroyMethod?=?null;
????????try?{
????????????//?獲取?destroy-method?方法對象
????????????destroyMethod?=?bean.getClass().getMethod(destroyMethodName);?
????????}?catch?(NoSuchMethodException?ex)?{
????????????throw?new?BeanDefinitionStoreException(...);
????????}
????????
????????//?調(diào)用方法
????????try?{
????????????if?(destroyMethod?!=?null)?{
????????????????destroyMethod.invoke(bean);
????????????}
????????}?catch?(...)?{
????????????throw?new?BeanCreationException(...);?
????????}
????}?
????
}
面試官:棒!最后,Spring Bean 的作用域都有哪些?如何控制 Bean 的生命周期?
候選人: Spring Bean 的作用域有 5 種:
- singleton:單例,整個 Spring 容器中只有一個 Bean 實例。
- prototype:原型,每次獲取 Bean 都會創(chuàng)建一個新的實例。
- request:每個 HTTP 請求都會創(chuàng)建一個 Bean 實例。
- session:每個 HTTP 會話都會創(chuàng)建一個 Bean 實例。
- global-session:每個全局 HTTP 會話都會創(chuàng)建一個 Bean 實例。
我們可以通過 scope 屬性控制 Bean 的作用域,從而影響其生命周期:
<bean?id="..."?class="..."?scope="prototype"/>
此外,我們還可以自定義 Bean 的初始化和銷毀方法,在 Bean 作用域開始和結(jié)束時觸發(fā):
<bean?id="..."?class="..."?scope="prototype"?
????init-method="start"?destroy-method="end">
</bean>
這樣我們就可以在 start() 方法中執(zhí)行初始化邏輯,在 end() 方法中執(zhí)行清理工作,從而精確控制 Bean 的生命周期。
面試官:很全面,佩服佩服!如果再給你一個機(jī)會,你覺得還可以在哪些方面加深對 Spring Bean 生命周期的理解?
候選人: 這里有幾個方面可以進(jìn)一步加深對 Spring Bean 生命周期的理解:
- BeanPostProcessor:這個接口可以監(jiān)聽 Bean 的初始化前后,提供了擴(kuò)展點可以在 Bean 初始化前后進(jìn)行一些處理。這也是 Spring AOP 的底層原理之一。
- 了解 BeanFactoryPostProcessor:這個接口可以監(jiān)聽 BeanDefinition 的加載,可以在 Bean 實例化前修改 BeanDefinition 的屬性。
-
理解 Bean 的加載時機(jī):在 Spring 容器啟動時,默認(rèn)會立即加載 singleton 作用域的 Bean,而其他作用域的 Bean 會延遲加載, singleton 作用域的 Bean 也支持延遲加載。這就要涉及到Spring 的
lazy-init屬性設(shè)置。 - 了解 Bean 為什么要有不同的作用域:每個作用域適合的場景是什么,選擇不同作用域會對 Bean 的生命周期產(chǎn)生怎樣的影響。
-
了解 Bean 之間的依賴關(guān)系對生命周期的影響:比如 A ?Bean 的初始化依賴 B Bean,那么 A Bean 的初始化也會延遲到 B Bean 初始化完畢后。這涉及到 Spring 的
depends-on屬性配置。 - 了解自定義初始化和銷毀方法的具體應(yīng)用場景:什么情況下需要自定義這些方法,能在方法中完成什么樣的邏輯處理。
- 探索 BeanPostProcessor 和 BeanFactoryPostProcessor 的具體應(yīng)用:比如 Spring AOP、Spring 事件發(fā)布者等機(jī)制的實現(xiàn)。綜上,要全面理解 Spring Bean 的生命周期,除了知道每個階段的調(diào)用外,還需要對很多這個過程涉及到的其他知識點進(jìn)行深入學(xué)習(xí)和理解,這需要不斷實踐和總結(jié)。但只要把這些要點都串聯(lián)起來,對 Spring Bean 的生命周期控制就會很得心應(yīng)手了。
面試官:非常棒,這些點精彩極了!你的回答已經(jīng)很全面和深入,對 Spring Bean 生命周期有清晰理解,這些又是常見的面試重點,我相信面試一定會取得很好的表現(xiàn),加油!我們就聊到這里,很高興與你的交流,謝謝!
最近我在更新《面試1v1》系列文章,主要以場景化的方式,講解我們在面試中遇到的問題,致力于讓每一位工程師拿到自己心儀的offer,感興趣可以關(guān)注公眾號JavaPub追更!
《面試1v1》連載中...

