深入了解Spring的Bean生命周期
源碼下載
什么是 Spring Bean 的生命周期
對于普通的 Java 對象,當(dāng) new 的時候創(chuàng)建對象,然后該對象就能夠使用了。一旦該對象不再被使用,則由 Java 自動進行垃圾回收。
而 Spring 中的對象是 bean,bean 和普通的 Java 對象沒啥大的區(qū)別,只不過 Spring 不再自己去 new 對象了,而是由 IoC 容器去幫助我們實例化對象并且管理它,我們需要哪個對象,去問 IoC 容器要即可。IoC 其實就是解決對象之間的耦合問題,Spring Bean 的生命周期完全由容器控制。
Bean的生命周期
Spring bean的生命周期階段是:

- 1.
bean定義:就是從xml或注解定位資源加載讀取bean的元信息并定義成一個BeanDefinition對象 - 2.
bean注冊:將BeanDefinition對象根據(jù)相應(yīng)的規(guī)則放到緩存池map中 - 3.
實例化:根據(jù)BeanDefinition實例化真正的bean,即是調(diào)用構(gòu)造函數(shù) - 4.
依賴注入:屬性賦值調(diào)用setter方法,即是依賴注入(DI) - 5.
初始化: 初始化是用戶能自定義擴展的階段 - 6.
銷毀: 銷毀是用戶能自定義擴展的階段
注:其他都是在這階段前后的擴展點
Spring角度查看bean的定義與注冊


refresh()
public void refresh() throws BeansException, IllegalStateException {
synchronized(this.startupShutdownMonitor) {
StartupStep contextRefresh = this.applicationStartup.start("spring.context.refresh");
// 準備Bean初始化相關(guān)的環(huán)境信息,其內(nèi)部提供了一個空實現(xiàn)的initPropertySources()方法用于提供給用戶一個更改相關(guān)環(huán)境信息的機會
this.prepareRefresh();
// 創(chuàng)建BeanFactory實例,并且注冊相關(guān)的bean信息
ConfigurableListableBeanFactory beanFactory = this.obtainFreshBeanFactory();
// 注冊Aware和Processor實例,并且注冊了后續(xù)處理請求所需的一些Editor信息
this.prepareBeanFactory(beanFactory);
try {
// 提供的一個空方法,用于供給子類對已經(jīng)生成的BeanFactory的一些信息進行定制
this.postProcessBeanFactory(beanFactory);
StartupStep beanPostProcess = this.applicationStartup.start("spring.context.beans.post-process");
// 調(diào)用BeanFactoryPostProcessor及其子接口的相關(guān)方法,這些接口提供了一個入口,提供給了調(diào)用方一個修改已經(jīng)生成的BeanDefinition的入口
this.invokeBeanFactoryPostProcessors(beanFactory);
// 對BeanPostProcessor進行注冊
this.registerBeanPostProcessors(beanFactory);
beanPostProcess.end();
// 初始化國際化所需的bean信息
this.initMessageSource();
// 初始化事件廣播器的bean信息
this.initApplicationEventMulticaster();
// 提供的一個空方法,供給子類用于提供自定義的bean信息,或者修改已有的bean信息
this.onRefresh();
// 注冊事件監(jiān)聽器
this.registerListeners();
// 對已經(jīng)注冊的非延遲(配置文件指定)bean的實例化
this.finishBeanFactoryInitialization(beanFactory);
// 清除緩存的資源信息,初始化一些聲明周期相關(guān)的bean,并且發(fā)布Context已被初始化的事件
this.finishRefresh();
} catch (BeansException var10) {
if (this.logger.isWarnEnabled()) {
this.logger.warn("Exception encountered during context initialization - cancelling refresh attempt: " + var10);
}
// 發(fā)生異常則銷毀已經(jīng)生成的bean
this.destroyBeans();
// 重置refresh字段信息
this.cancelRefresh(var10);
throw var10;
} finally {
// 初始化一些緩存信息
this.resetCommonCaches();
contextRefresh.end();
}
}
}






SpringBoot角度查看bean定義和注冊



1. 自動加載配置類

2. bean定義和注冊


注:springboot只是比spring多了自動配置相關(guān)流程,在spring上做了一層邏輯封裝。
實例化,依賴注入,初始化
AbstractAutowireCapableBeanFactory為AutowireCapableBeanFactory接口的一個實現(xiàn)類,其中AbstractAutowireCapableBeanFactory實現(xiàn)類的一個方法doCreateBean()
//位置:AbstractAutowireCapableBeanFactory#doCreateBean
protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) throws BeanCreationException {
BeanWrapper instanceWrapper = null;
if (mbd.isSingleton()) {
instanceWrapper = (BeanWrapper)this.factoryBeanInstanceCache.remove(beanName);
}
if (instanceWrapper == null) {
// 實例化階段
instanceWrapper = this.createBeanInstance(beanName, mbd, args);
}
...
Object exposedObject = bean;
try {
// 依賴注入,屬性賦值階段
this.populateBean(beanName, mbd, instanceWrapper);
// 初始化階段
exposedObject = this.initializeBean(beanName, exposedObject, mbd);
} catch (Throwable var18) {
...
}
...
}可以發(fā)現(xiàn),分別調(diào)用三種方法:
- createBeanInstance() -> 實例化
- populateBean() -> 依賴注入
- initializeBean() -> 初始化
銷毀
銷毀階段是在容器關(guān)閉時調(diào)用的,在ConfigurableApplicationContext#close()
至于xxxAware,BeanPostProcessor,BeanFactoryPostProcessor等類,只不過是對主流程的一系列擴展點而已。
Bean的生命周期的擴展點
Spring Bean 的生命周期的擴展點很多,這里不可能全部列出來,只說核心的擴展點。這也就是為什么 Spring 的擴展性很好的原因,開了很多的口子,盡可能讓某個功能高內(nèi)聚松耦合,用戶需要哪個功能就用哪個,而不是直接來一個大而全的東西。
Bean級別
這些接口的實現(xiàn)類是基于 Bean 的,只要實現(xiàn)了這些接口的Bean才起作用。
- BeanNameAware
- BeanFactoryAware
- ApplicationContextAware
- InitializingBean
- DisposableBean
還要很多的xxxAware,這些不常用,下面生命周期測試就不加上,如:
- BeanClassLoaderAware
- EnvironmentAware
- EmbeddedValueResolverAware
- ResourceLoaderAware
- ApplicationEventPublisherAware
- MessageSourceAware
- ServletContextAware
容器級別
這些接口的實現(xiàn)類是獨立于 Bean 的,并且會注冊到 Spring 容器中。一般稱它們的實現(xiàn)類為后置處理器。
在 Spring 容器創(chuàng)建任何 Bean 的時候,這些后置處理器都會發(fā)生作用
BeanPostProcessor
InstantiationAwareBeanPostProcessor(InstantiationAwareBeanPostProcessor 是繼承了 BeanPostProcessor)
工廠后處理器接口也是容器級的。在應(yīng)用上下文裝配配置文件之后立即調(diào)用:
- AspectJWeavingEnabler
- ConfigurationClassPostProcessor
- CustomAutowireConfigurer
常用接口
InstantiationAwareBeanPostProcessor
該類是 BeanPostProcessor 的子接口,常用的有如下三個方法:
- postProcessBeforeInstantiation(Class beanClass, String beanName):在bean實例化之前調(diào)用
- postProcessProperties(PropertyValues pvs, Object bean, String beanName):在bean實例化之后、設(shè)置屬性前調(diào)用
- postProcessAfterInstantiation(Class beanClass, String beanName):在bean實例化之后調(diào)用
BeanNameAware
BeanNameAware接口是為了讓自身Bean能夠感知到,只有一個方法setBeanName(String name),獲取到自身在Spring容器中的id或name屬性。
BeanFactoryAware
該接口只有一個方法setBeanFactory(BeanFactory beanFactory),用來獲取當(dāng)前環(huán)境中的 BeanFactory,可以對工廠中的所有bean進行擴展。
ApplicationContextAware
該接口只有一個方法setApplicationContext(ApplicationContext applicationContext),用來獲取當(dāng)前環(huán)境中的 ApplicationContext,可以對整個容器進行擴展。
注:有時候并不會調(diào)用該接口,這要根據(jù)你的IOC容器來決定:Spring IOC容器最低要求是實現(xiàn)BeanFactory接口,而不是實現(xiàn)ApplicationContext接口,對于那些沒有實現(xiàn)ApplicationContext接口的容器,在生命周期對應(yīng)的ApplicationContextAware定義的方法也是不會調(diào)用的,只要實現(xiàn)了ApplicationContext接口的容器,才會調(diào)用。
BeanPostProcessor
postProcessBeforeInitialization(Object bean, String beanName):在初始化之前調(diào)用此方法,Spring 的 AOP 就是利用它實現(xiàn)的。
postProcessAfterInitialization(Object bean, String beanName):在初始化之后調(diào)用此方法
InitializingBean
該接口只有一個方法afterPropertiesSet(),在屬性注入完成后調(diào)用。
凡是繼承該接口的類,在初始化bean的時候都會執(zhí)行該方法,可以進行一些屬性配置等工作。
InitializingBean 對應(yīng)生命周期的初始化階段,在源碼的invokeInitMethods(beanName, wrappedBean, mbd)方法中調(diào)用。
DisposableBean
該接口的作用是在對象銷毀時調(diào)用,可以做一些資源銷毀操作。
DisposableBean 類似于InitializingBean,對應(yīng)生命周期的銷毀階段,以ConfigurableApplicationContext#close()方法作為入口,實現(xiàn)是通過循環(huán)取所有實現(xiàn)了DisposableBean接口的Bean然后調(diào)用其destroy()方法
常用注解
@Bean(initMethod = "initMethod", destroyMethod = "destroyMethod")
@Bean聲明一個bean,配合@Configuration注解使用
initMethod:聲明bean初始化時回調(diào)一個方法,該方法需要程序員編寫
destroyMethod:聲明bean銷毀時回調(diào)一個方法,該方法需要程序員編寫
@PostConstruct
bean的一個基于注解的初始化方法
@PreDestroy
bean的一個基于注解的銷毀方法
案例分析
聲明一個bean
@Configuration
public class BeanInitAndDestroyConfig {
/**
* @return 這里沒有指定bean名字,默認是方法名
*/
@Description("測試bean的生命周期")
@Bean(initMethod = "initMethod", destroyMethod = "destroyMethod")
public MyService myServiceBeanName() {//入?yún)?shù)可注入其他依賴
return new MyService();
}
}- 聲明一個名為:myServiceBeanName的bean
- initMethod:bean的初始化方法為:initMethod
- destroyMethod:bean的銷毀方法為:destroyMethod
Animal實現(xiàn)類

這里只是想用來說明 @Qualifier注解能根據(jù)bean名稱匹配。
我的服務(wù)類
即是針對當(dāng)前bean只調(diào)用一次的接口
/**
* @Description: bean生命周期測試:這些接口只針對當(dāng)前bean
* @Author: jianweil
* @date: 2021/12/8 9:46
*/
public class MyService implements Person, BeanNameAware, BeanFactoryAware, ApplicationContextAware, InitializingBean, DisposableBean {
private Animal animal = null;
private ApplicationContext applicationContext;
/**
*接口規(guī)定方法
*/
@Override
public void service() {
this.animal.use();
}
public MyService() {
System.out.println("2. [bean實例化]:"+this.getClass().getSimpleName()+"----------構(gòu)造方法");
}
/**
*接口規(guī)定方法:注入依賴
*/
@Override
@Autowired
@Qualifier("dog")
public void setAnimal(Animal animal) {
System.out.println("5. [bean屬性賦值]:dog----依賴注入");
this.animal = animal;
}
@Override
public void setBeanName(String s) {
System.out.println("6. 調(diào)用【BeanNameAware】--setBeanName:"+s);
}
@Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
System.out.println("7. 調(diào)用【BeanFactoryAware】--setBeanFactory");
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
System.out.println("8. 調(diào)用【ApplicationContextAware】--setApplicationContext");
}
/**
* 初始化1
*/
@PostConstruct
public void myInit() {
System.out.println("10. [初始化] 注解@PostConstruct自定義初始化方法[myInit]");
}
/**
* 初始化2
*/
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("11. [初始化] 接口InitializingBean方法[afterPropertiesSet]");
}
/**
* 初始化3
*/
public void initMethod() {
System.out.println("12. [初始化] 注解@Bean自定義初始化方法[initMethod]");
}
/**
* 銷毀1
*/
@PreDestroy
public void myDestroy() {
System.out.println("14. [銷毀] 注解@PreDestroy自定義銷毀方法[myDestroy]");
}
/**
* 銷毀2
*/
@Override
public void destroy() throws Exception {
System.out.println("15. [銷毀] 接口DisposableBean方法[destroy]");
}
/**
* 銷毀3
*/
public void destroyMethod() {
System.out.println("16. [銷毀] 注解@Bean自定義銷毀方法[destroyMethod]");
}
}這里實現(xiàn)的接口只作用于當(dāng)前bean(即是上面@bean定義的bean名為myDefineBeanName)生命周期
后置處理器
每個bean生命周期都執(zhí)行一次
后置處理器是作用于ioc容器中所有bean的生命周期。
/**
* @Description: todo
* @Author: jianweil
* @date: 2021/12/20 17:20
*/
@Component
public class MyInstantiationAwareBeanPostProcessor implements InstantiationAwareBeanPostProcessor {
@Override
public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
if ("myServiceBeanName".equals(beanName) || "dog".equals(beanName)) {
System.out.println("============================InstantiationAwareBeanPostProcessor-開始======================");
System.out.println("1. [容器級別每個bean都回調(diào)] 調(diào)用 InstantiationAwareBeanPostProcessor.postProcessBeforeInstantiation() 方法:beanName為"+beanName);
}
return null;
}
@Override
public boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {
if ("myServiceBeanName".equals(beanName) || "dog".equals(beanName)) {
System.out.println("3. [容器級別每個bean都回調(diào)] 調(diào)用 InstantiationAwareBeanPostProcessor.postProcessAfterInstantiation() 方法:beanName為"+beanName);
}
return true;
}
@Override
public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) throws BeansException {
if ("myServiceBeanName".equals(beanName) || "dog".equals(beanName)) {
System.out.println("4. [容器級別每個bean都回調(diào)] 調(diào)用 InstantiationAwareBeanPostProcessor.postProcessProperties() 方法:beanName為"+beanName);
System.out.println("============================InstantiationAwareBeanPostProcessor-結(jié)束======================");
}
return null;
}
}/**
* @Description: 后置bean的初始化器:所有的bean都會攔截執(zhí)行
* @Author: jianweil
* @date: 2021/12/8 9:46
*/
@Component
public class MyBeanPostProcessor implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
//這里過濾掉springboot自動配置的bean,只打印我們項目的bean情況
if ("myServiceBeanName".equals(beanName) || "dog".equals(beanName)) {
System.out.println("9. [容器級別每個bean都回調(diào)] 調(diào)用 BeanPostProcessor.postProcessBeforeInitialization 方法:beanName為" + beanName);
}
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if ("myServiceBeanName".equals(beanName) || "dog".equals(beanName)) {
System.out.println("13. [容器級別每個bean都回調(diào)] 調(diào)用 BeanPostProcessor.postProcessAfterInitialization 方法:beanName為" + beanName);
}
return bean;
}
}工廠后置處理器
容器級別,只允許一次
@Component
public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
System.out.println("0. [容器級別只調(diào)用一次] 調(diào)用 BeanFactoryPostProcessor.postProcessBeanFactory() 方法");
}
}輸出結(jié)果和結(jié)果解讀
“//”標(biāo)記為解讀
//容器級別的工廠后置處理器,只在應(yīng)用上下文裝配配置文件之后立即調(diào)用1次
0. [容器級別只調(diào)用一次] 調(diào)用 BeanFactoryPostProcessor.postProcessBeanFactory() 方法
//因為我們生命過程只打印("myServiceBeanName".equals(beanName) || "dog".equals(beanName)),所有貓只有構(gòu)造方法打印了
貓----------構(gòu)造方法
//###############################dog的生命周期###############################################
//后置處理器,容器級別,作用于所有bean
============================InstantiationAwareBeanPostProcessor-開始======================
1. [容器級別每個bean都回調(diào)] 調(diào)用 InstantiationAwareBeanPostProcessor.postProcessBeforeInstantiation() 方法:beanName為dog
//狗的實例化
狗----------構(gòu)造方法
//后置處理器,容器級別,作用于所有bean
3. [容器級別每個bean都回調(diào)] 調(diào)用 InstantiationAwareBeanPostProcessor.postProcessAfterInstantiation() 方法:beanName為dog
//后置處理器,容器級別,作用于所有bean
4. [容器級別每個bean都回調(diào)] 調(diào)用 InstantiationAwareBeanPostProcessor.postProcessProperties() 方法:beanName為dog
============================InstantiationAwareBeanPostProcessor-結(jié)束======================
//后置處理器,容器級別,作用于所有bean
9. [容器級別每個bean都回調(diào)] 調(diào)用 BeanPostProcessor.postProcessBeforeInitialization 方法:beanName為dog
//后置處理器,容器級別,作用于所有bean
13. [容器級別每個bean都回調(diào)] 調(diào)用 BeanPostProcessor.postProcessAfterInitialization 方法:beanName為dog
//###############################dog的bean完成,開始myServiceBeanName###############################################
//后置處理器,容器級別,作用于所有bean
============================InstantiationAwareBeanPostProcessor-開始======================
1. [容器級別每個bean都回調(diào)] 調(diào)用 InstantiationAwareBeanPostProcessor.postProcessBeforeInstantiation() 方法:beanName為myServiceBeanName
//實例化
2. [bean實例化]:MyService----------構(gòu)造方法
//后置處理器,容器級別,作用于所有bean
3. [容器級別每個bean都回調(diào)] 調(diào)用 InstantiationAwareBeanPostProcessor.postProcessAfterInstantiation() 方法:beanName為myServiceBeanName
//后置處理器,容器級別,作用于所有bean
4. [容器級別每個bean都回調(diào)] 調(diào)用 InstantiationAwareBeanPostProcessor.postProcessProperties() 方法:beanName為myServiceBeanName
============================InstantiationAwareBeanPostProcessor-結(jié)束======================
//屬性賦值,即是依賴注入
5. [bean屬性賦值]:dog----依賴注入
//bean級別,bean:myServiceBeanName實現(xiàn)了接口BeanNameAware
6. 調(diào)用【BeanNameAware】--setBeanName:myServiceBeanName
//bean級別
7. 調(diào)用【BeanFactoryAware】--setBeanFactory
//bean級別
8. 調(diào)用【ApplicationContextAware】--setApplicationContext
//后置處理器,容器級別,作用于所有bean:初始化前處理
9. [容器級別每個bean都回調(diào)] 調(diào)用 BeanPostProcessor.postProcessBeforeInitialization 方法:beanName為myServiceBeanName
//初始化
10. [初始化] 注解@PostConstruct自定義初始化方法[myInit]
11. [初始化] 接口InitializingBean方法[afterPropertiesSet]
12. [初始化] 注解@Bean自定義初始化方法[initMethod]
//后置處理器,容器級別,作用于所有bean:初始化后處理
13. [容器級別每個bean都回調(diào)] 調(diào)用 BeanPostProcessor.postProcessAfterInitialization 方法:beanName為myServiceBeanName
//容器環(huán)境加載完成,這時可以使用所有bean
2021-12-21 11:18:42.994 INFO 18956 --- [ main] c.l.s.SpringbootBeanLifecycleApplication : Started SpringbootBeanLifecycleApplication in 0.719 seconds (JVM running for 1.312)
//銷毀
14. [銷毀] 注解@PreDestroy自定義銷毀方法[myDestroy]
15. [銷毀] 接口DisposableBean方法[destroy]
16. [銷毀] 注解@Bean自定義銷毀方法[destroyMethod]
Process finished with exit code 0
Bean生命周期圖

了解 Spring 生命周期的意義就在于,可以利用 Bean 在其存活期間的指定時刻完成一些相關(guān)操作。一般情況下,會在 Bean 被初始化后和被銷毀前執(zhí)行一些相關(guān)操作。
以上就是深入了解Spring的Bean生命周期的詳細內(nèi)容,更多關(guān)于Spring Bean生命周期的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
mybatis@insert?注解如何判斷insert或是update
這篇文章主要介紹了mybatis@insert?注解如何判斷insert或是update,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-07-07
淺析Java的Hibernate框架中的繼承關(guān)系設(shè)計
這篇文章主要介紹了Java的Hibernate框架中的繼承關(guān)系設(shè)計,Hibernate是Java的SSH三大web開發(fā)框架之一,需要的朋友可以參考下2015-12-12
Kafka常用命令之kafka-console-consumer.sh解讀
這篇文章主要介紹了Kafka常用命令之kafka-console-consumer.sh解讀,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2023-03-03
如何解決org.apache.jasper.JasperException:無法為JSP編譯類詳解
這篇文章主要給大家介紹了關(guān)于如何解決org.apache.jasper.JasperException:無法為JSP編譯類的相關(guān)資料,原因可能是JSP文件的語法錯誤、類路徑問題或其他配置問題,建議檢查JSP文件的語法、類路徑配置和其他相關(guān)配置,需要的朋友可以參考下2023-06-06
Java并發(fā)系列之CyclicBarrier源碼分析
這篇文章主要為大家詳細分析了Java并發(fā)系列之CyclicBarrier源碼,具有一定的參考價值,感興趣的小伙伴們可以參考一下2018-03-03
Java數(shù)組隊列及環(huán)形數(shù)組隊列超詳細講解
隊列是一個有序列表,可以用數(shù)組和鏈表來實現(xiàn),隊列有一個原則。即:先存入隊列的數(shù)據(jù)要先取出,后存入的要后取出,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)吧2022-09-09

