深入瞭解Spring的Bean生命周期
源碼下載
本章節源碼github
什麼是 Spring Bean 的生命周期
對於普通的 Java 對象,當 new 的時候創建對象,然後該對象就能夠使用瞭。一旦該對象不再被使用,則由 Java 自動進行垃圾回收。
而 Spring 中的對象是 bean,bean 和普通的 Java 對象沒啥大的區別,隻不過 Spring 不再自己去 new 對象瞭,而是由 IoC 容器去幫助我們實例化對象並且管理它,我們需要哪個對象,去問 IoC 容器要即可。IoC 其實就是解決對象之間的耦合問題,Spring Bean 的生命周期完全由容器控制。
Bean的生命周期
Spring bean的生命周期階段是:
- 1.
bean定義
:就是從xml或註解定位資源加載讀取bean的元信息並定義成一個BeanDefinition對象 - 2.
bean註冊
:將BeanDefinition對象根據相應的規則放到緩存池map中 - 3.
實例化
:根據BeanDefinition實例化真正的bean,即是調用構造函數 - 4.
依賴註入
:屬性賦值調用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初始化相關的環境信息,其內部提供瞭一個空實現的initPropertySources()方法用於提供給用戶一個更改相關環境信息的機會 this.prepareRefresh(); // 創建BeanFactory實例,並且註冊相關的bean信息 ConfigurableListableBeanFactory beanFactory = this.obtainFreshBeanFactory(); // 註冊Aware和Processor實例,並且註冊瞭後續處理請求所需的一些Editor信息 this.prepareBeanFactory(beanFactory); try { // 提供的一個空方法,用於供給子類對已經生成的BeanFactory的一些信息進行定制 this.postProcessBeanFactory(beanFactory); StartupStep beanPostProcess = this.applicationStartup.start("spring.context.beans.post-process"); // 調用BeanFactoryPostProcessor及其子接口的相關方法,這些接口提供瞭一個入口,提供給瞭調用方一個修改已經生成的BeanDefinition的入口 this.invokeBeanFactoryPostProcessors(beanFactory); // 對BeanPostProcessor進行註冊 this.registerBeanPostProcessors(beanFactory); beanPostProcess.end(); // 初始化國際化所需的bean信息 this.initMessageSource(); // 初始化事件廣播器的bean信息 this.initApplicationEventMulticaster(); // 提供的一個空方法,供給子類用於提供自定義的bean信息,或者修改已有的bean信息 this.onRefresh(); // 註冊事件監聽器 this.registerListeners(); // 對已經註冊的非延遲(配置文件指定)bean的實例化 this.finishBeanFactoryInitialization(beanFactory); // 清除緩存的資源信息,初始化一些聲明周期相關的bean,並且發佈Context已被初始化的事件 this.finishRefresh(); } catch (BeansException var10) { if (this.logger.isWarnEnabled()) { this.logger.warn("Exception encountered during context initialization - cancelling refresh attempt: " + var10); } // 發生異常則銷毀已經生成的bean this.destroyBeans(); // 重置refresh字段信息 this.cancelRefresh(var10); throw var10; } finally { // 初始化一些緩存信息 this.resetCommonCaches(); contextRefresh.end(); } } }
SpringBoot角度查看bean定義和註冊
1. 自動加載配置類
2. bean定義和註冊
註:springboot隻是比spring多瞭自動配置相關流程,在spring上做瞭一層邏輯封裝。
實例化,依賴註入,初始化
AbstractAutowireCapableBeanFactory為AutowireCapableBeanFactory接口的一個實現類,其中AbstractAutowireCapableBeanFactory實現類的一個方法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) { ... } ... }
可以發現,分別調用三種方法:
- createBeanInstance() -> 實例化
- populateBean() -> 依賴註入
- initializeBean() -> 初始化
銷毀
銷毀階段是在容器關閉時調用的,在ConfigurableApplicationContext#close()
至於xxxAware,BeanPostProcessor,BeanFactoryPostProcessor等類,隻不過是對主流程的一系列擴展點而已。
Bean的生命周期的擴展點
Spring Bean 的生命周期的擴展點很多,這裡不可能全部列出來,隻說核心的擴展點。這也就是為什麼 Spring 的擴展性很好的原因,開瞭很多的口子,盡可能讓某個功能高內聚松耦合,用戶需要哪個功能就用哪個,而不是直接來一個大而全的東西。
Bean級別
這些接口的實現類是基於 Bean 的,隻要實現瞭這些接口的Bean才起作用。
- BeanNameAware
- BeanFactoryAware
- ApplicationContextAware
- InitializingBean
- DisposableBean
還要很多的xxxAware,這些不常用,下面生命周期測試就不加上,如:
- BeanClassLoaderAware
- EnvironmentAware
- EmbeddedValueResolverAware
- ResourceLoaderAware
- ApplicationEventPublisherAware
- MessageSourceAware
- ServletContextAware
容器級別
這些接口的實現類是獨立於 Bean 的,並且會註冊到 Spring 容器中。一般稱它們的實現類為後置處理器。
在 Spring 容器創建任何 Bean 的時候,這些後置處理器都會發生作用
BeanPostProcessor
InstantiationAwareBeanPostProcessor(InstantiationAwareBeanPostProcessor 是繼承瞭 BeanPostProcessor)
工廠後處理器接口也是容器級的。在應用上下文裝配配置文件之後立即調用:
- AspectJWeavingEnabler
- ConfigurationClassPostProcessor
- CustomAutowireConfigurer
常用接口
InstantiationAwareBeanPostProcessor
該類是 BeanPostProcessor 的子接口,常用的有如下三個方法:
- postProcessBeforeInstantiation(Class beanClass, String beanName):在bean實例化之前調用
- postProcessProperties(PropertyValues pvs, Object bean, String beanName):在bean實例化之後、設置屬性前調用
- postProcessAfterInstantiation(Class beanClass, String beanName):在bean實例化之後調用
BeanNameAware
BeanNameAware接口是為瞭讓自身Bean能夠感知到,隻有一個方法setBeanName(String name),獲取到自身在Spring容器中的id或name屬性。
BeanFactoryAware
該接口隻有一個方法setBeanFactory(BeanFactory beanFactory),用來獲取當前環境中的 BeanFactory,可以對工廠中的所有bean進行擴展。
ApplicationContextAware
該接口隻有一個方法setApplicationContext(ApplicationContext applicationContext),用來獲取當前環境中的 ApplicationContext,可以對整個容器進行擴展。
註:有時候並不會調用該接口,這要根據你的IOC容器來決定:Spring IOC容器最低要求是實現BeanFactory接口,而不是實現ApplicationContext接口,對於那些沒有實現ApplicationContext接口的容器,在生命周期對應的ApplicationContextAware定義的方法也是不會調用的,隻要實現瞭ApplicationContext接口的容器,才會調用。
BeanPostProcessor
postProcessBeforeInitialization(Object bean, String beanName):在初始化之前調用此方法,Spring 的 AOP 就是利用它實現的。
postProcessAfterInitialization(Object bean, String beanName):在初始化之後調用此方法
InitializingBean
該接口隻有一個方法afterPropertiesSet(),在屬性註入完成後調用。
凡是繼承該接口的類,在初始化bean的時候都會執行該方法,可以進行一些屬性配置等工作。
InitializingBean 對應生命周期的初始化階段,在源碼的invokeInitMethods(beanName, wrappedBean, mbd)方法中調用。
DisposableBean
該接口的作用是在對象銷毀時調用,可以做一些資源銷毀操作。
DisposableBean 類似於InitializingBean,對應生命周期的銷毀階段,以ConfigurableApplicationContext#close()方法作為入口,實現是通過循環取所有實現瞭DisposableBean接口的Bean然後調用其destroy()方法
常用註解
@Bean(initMethod = "initMethod", destroyMethod = "destroyMethod")
@Bean聲明一個bean,配合@Configuration註解使用
initMethod:聲明bean初始化時回調一個方法,該方法需要程序員編寫
destroyMethod:聲明bean銷毀時回調一個方法,該方法需要程序員編寫
@PostConstruct
bean的一個基於註解的初始化方法
@PreDestroy
bean的一個基於註解的銷毀方法
案例分析
聲明一個bean
@Configuration public class BeanInitAndDestroyConfig { /** * @return 這裡沒有指定bean名字,默認是方法名 */ @Description("測試bean的生命周期") @Bean(initMethod = "initMethod", destroyMethod = "destroyMethod") public MyService myServiceBeanName() {//入參數可註入其他依賴 return new MyService(); } }
- 聲明一個名為:myServiceBeanName的bean
- initMethod:bean的初始化方法為:initMethod
- destroyMethod:bean的銷毀方法為:destroyMethod
Animal實現類
這裡隻是想用來說明 @Qualifier註解能根據bean名稱匹配。
我的服務類
即是針對當前bean隻調用一次的接口
/** * @Description: bean生命周期測試:這些接口隻針對當前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; /** *接口規定方法 */ @Override public void service() { this.animal.use(); } public MyService() { System.out.println("2. [bean實例化]:"+this.getClass().getSimpleName()+"----------構造方法"); } /** *接口規定方法:註入依賴 */ @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. 調用【BeanNameAware】--setBeanName:"+s); } @Override public void setBeanFactory(BeanFactory beanFactory) throws BeansException { System.out.println("7. 調用【BeanFactoryAware】--setBeanFactory"); } @Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { this.applicationContext = applicationContext; System.out.println("8. 調用【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]"); } }
這裡實現的接口隻作用於當前bean(即是上面@bean定義的bean名為myDefineBeanName)生命周期
後置處理器
每個bean生命周期都執行一次
後置處理器是作用於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都回調] 調用 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都回調] 調用 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都回調] 調用 InstantiationAwareBeanPostProcessor.postProcessProperties() 方法:beanName為"+beanName); System.out.println("============================InstantiationAwareBeanPostProcessor-結束======================"); } return null; } }
/** * @Description: 後置bean的初始化器:所有的bean都會攔截執行 * @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都回調] 調用 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都回調] 調用 BeanPostProcessor.postProcessAfterInitialization 方法:beanName為" + beanName); } return bean; } }
工廠後置處理器
容器級別,隻允許一次
@Component public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor { @Override public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException { System.out.println("0. [容器級別隻調用一次] 調用 BeanFactoryPostProcessor.postProcessBeanFactory() 方法"); } }
輸出結果和結果解讀
“//”標記為解讀
//容器級別的工廠後置處理器,隻在應用上下文裝配配置文件之後立即調用1次 0. [容器級別隻調用一次] 調用 BeanFactoryPostProcessor.postProcessBeanFactory() 方法 //因為我們生命過程隻打印("myServiceBeanName".equals(beanName) || "dog".equals(beanName)),所有貓隻有構造方法打印瞭 貓----------構造方法 //###############################dog的生命周期############################################### //後置處理器,容器級別,作用於所有bean ============================InstantiationAwareBeanPostProcessor-開始====================== 1. [容器級別每個bean都回調] 調用 InstantiationAwareBeanPostProcessor.postProcessBeforeInstantiation() 方法:beanName為dog //狗的實例化 狗----------構造方法 //後置處理器,容器級別,作用於所有bean 3. [容器級別每個bean都回調] 調用 InstantiationAwareBeanPostProcessor.postProcessAfterInstantiation() 方法:beanName為dog //後置處理器,容器級別,作用於所有bean 4. [容器級別每個bean都回調] 調用 InstantiationAwareBeanPostProcessor.postProcessProperties() 方法:beanName為dog ============================InstantiationAwareBeanPostProcessor-結束====================== //後置處理器,容器級別,作用於所有bean 9. [容器級別每個bean都回調] 調用 BeanPostProcessor.postProcessBeforeInitialization 方法:beanName為dog //後置處理器,容器級別,作用於所有bean 13. [容器級別每個bean都回調] 調用 BeanPostProcessor.postProcessAfterInitialization 方法:beanName為dog //###############################dog的bean完成,開始myServiceBeanName############################################### //後置處理器,容器級別,作用於所有bean ============================InstantiationAwareBeanPostProcessor-開始====================== 1. [容器級別每個bean都回調] 調用 InstantiationAwareBeanPostProcessor.postProcessBeforeInstantiation() 方法:beanName為myServiceBeanName //實例化 2. [bean實例化]:MyService----------構造方法 //後置處理器,容器級別,作用於所有bean 3. [容器級別每個bean都回調] 調用 InstantiationAwareBeanPostProcessor.postProcessAfterInstantiation() 方法:beanName為myServiceBeanName //後置處理器,容器級別,作用於所有bean 4. [容器級別每個bean都回調] 調用 InstantiationAwareBeanPostProcessor.postProcessProperties() 方法:beanName為myServiceBeanName ============================InstantiationAwareBeanPostProcessor-結束====================== //屬性賦值,即是依賴註入 5. [bean屬性賦值]:dog----依賴註入 //bean級別,bean:myServiceBeanName實現瞭接口BeanNameAware 6. 調用【BeanNameAware】--setBeanName:myServiceBeanName //bean級別 7. 調用【BeanFactoryAware】--setBeanFactory //bean級別 8. 調用【ApplicationContextAware】--setApplicationContext //後置處理器,容器級別,作用於所有bean:初始化前處理 9. [容器級別每個bean都回調] 調用 BeanPostProcessor.postProcessBeforeInitialization 方法:beanName為myServiceBeanName //初始化 10. [初始化] 註解@PostConstruct自定義初始化方法[myInit] 11. [初始化] 接口InitializingBean方法[afterPropertiesSet] 12. [初始化] 註解@Bean自定義初始化方法[initMethod] //後置處理器,容器級別,作用於所有bean:初始化後處理 13. [容器級別每個bean都回調] 調用 BeanPostProcessor.postProcessAfterInitialization 方法:beanName為myServiceBeanName //容器環境加載完成,這時可以使用所有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 在其存活期間的指定時刻完成一些相關操作。一般情況下,會在 Bean 被初始化後和被銷毀前執行一些相關操作。
以上就是深入瞭解Spring的Bean生命周期的詳細內容,更多關於Spring Bean生命周期的資料請關註WalkonNet其它相關文章!
推薦閱讀:
- Spring源碼解析之BeanPostProcessor知識總結
- Spring BeanPostProcessor(後置處理器)的用法
- 關於Spring BeanPostProcessor的執行順序
- Java Spring Bean的生命周期管理詳解
- 詳解Spring中Bean後置處理器(BeanPostProcessor)的使用