spring-bean的生命周期
參考:
作者:淺然_
https://blog.csdn.net/w_linux/article/details/80086950
spring就是一個能夠替你做很多事情的工廠,spring容器中的Bean就是該工廠的產品。要想使用Spring工廠生產和管理Bean,就需要在配置文件中指明需要哪些Bean,以及需要使用何種方式將這些Bean裝配到一起。
在IoC容器啟動之後,並不會馬上就實例化相應的bean,此時容器僅僅擁有所有對象的BeanDefinition(BeanDefinition:是容器依賴某些工具加載的XML配置信息進行解析和分析,並將分析後的信息編組為相應的BeanDefinition)。只有當getBean()調用時才是有可能觸發Bean實例化階段的活動
通過圖片了解一下bean的生命周期。
加載spring容器:BeanFactory
1.instantiate bean對象實例化
2.populate properties 封裝屬性
3.如果Bean實現BeanNameAware 執行 setBeanName
4.如果Bean實現BeanFactoryAware 執行setBeanFactory ,獲取Spring容器
5.如果存在類實現 BeanPostProcessor(後處理Bean) ,執行postProcessBeforeInitialization
6.如果Bean實現InitializingBean 執行 afterPropertiesSet
7.調用<bean init-method="init"> 指定初始化方法 init
8.如果存在類實現 BeanPostProcessor(處理Bean) ,執行postProcessAfterInitialization
執行業務處理
9.如果Bean實現 DisposableBean 執行 destroy
10.調用<bean destroy-method="customerDestroy"> 指定銷毀方法 customerDestroy
加載spring容器方式:應用上下文(類路徑裝載應用上下文與文件系統中裝載應用上下文,即類路徑與文件系統路徑)
參考:https://www.cnblogs.com/kenshinobiy/p/4652008.html
1、實例化一個Bean--也就是我們常說的new;
2、按照Spring上下文對實例化的Bean進行配置--也就是IOC註入;
3、如果這個Bean已經實現了BeanNameAware接口,會調用它實現的setBeanName(String)方法,此處傳遞的就是Spring配置文件中Bean的id值
4、如果這個Bean已經實現了BeanFactoryAware接口,會調用它實現的setBeanFactory(setBeanFactory(BeanFactory)傳遞的是Spring工廠自身(可以用這個方式來獲取其它Bean,只需在Spring配置文件中配置一個普通的Bean就可以);
5、如果這個Bean已經實現了ApplicationContextAware接口,會調用setApplicationContext(ApplicationContext)方法,傳入Spring上下文(同樣這個方式也可以實現步驟4的內容,但比4更好,因為ApplicationContext是BeanFactory的子接口,有更多的實現方法);
6、如果這個Bean關聯了BeanPostProcessor接口,將會調用postProcessBeforeInitialization(Object obj, String s)方法,BeanPostProcessor經常被用作是Bean內容的更改,並且由於這個是在Bean初始化結束時調用那個的方法,也可以被應用於內存或緩存技術;
7、如果Bean在Spring配置文件中配置了init-method屬性會自動調用其配置的初始化方法。
8、如果這個Bean關聯了BeanPostProcessor接口,將會調用postProcessAfterInitialization(Object obj, String s)方法、;
註:以上工作完成以後就可以應用這個Bean了,那這個Bean是一個Singleton的,所以一般情況下我們調用同一個id的Bean會是在內容地址相同的實例,當然在Spring配置文件中也可以配置非Singleton,這裏我們不做贅述。
9、當Bean不再需要時,會經過清理階段,如果Bean實現了DisposableBean這個接口,會調用那個其實現的destroy()方法;
10、最後,如果這個Bean的Spring配置中配置了destroy-method屬性,會自動調用其配置的銷毀方法。
以上10步驟可以作為面試或者筆試的模板,另外我們這裏描述的是應用Spring上下文Bean的生命周期,如果應用Spring的工廠也就是BeanFactory的話去掉第5步就Ok了。
說明
1. Bean生命周期要經歷很多階段,但這些階段大部分都是可選的。例如,某個Bean如果實現了BeanFactoryAware接口的setBeanFactory方法,那麽該Bean的生命就會經歷這個階段,如果不實現則沒有。
2. BeanFactoryPostProcessor接口與BeanPostProcessor接口的作用範圍是整個上下文環境中,使用方法是單獨新增一個類來實現這些接口,那麽在處理其他Bean的某些時刻就會回調響應的接口中的方法。
3、BeanNameAware、BeanFactoryAware、ApplicationContextAware的作用範圍的Bean範圍,即僅僅對實現了該接口的指定Bean有效,所有其使用方法是在要使用該功能的Bean自己來實現該接口。
4、InitializingBean的afterPropertiesSet()方法 與 自定義的inti-method指定的方法 兩個初始化方法作用是一樣的,我們完全可以使用其中的一種即可,一般情況我們使用自定義的inti-method指定的方法的方式,盡量少的去來Bean中實現某些接口,保持其獨立性,低耦合性,盡量不要與Spring代碼耦合在一起。DisposableBean的destory()方法 和自定義的destory-method指定的方法也是如此。
下面就解釋一下這些接口都有什麽作用:
參考:https://www.jianshu.com/p/d7e45100f934
https://www.cnblogs.com/xiaozhuanfeng/p/10790695.html(裏面有代碼)
BeanNameAware接口:
讓bean對name或id有知覺。即為了讓自身Bean能夠感知到,獲取到自身在Spring容器中的id或name屬性。
讓Bean獲取自己在BeanFactory配置中的名字(根據情況是id或者name)。
Spring自動調用。並且會在Spring自身完成Bean配置之後,且在調用任何Bean生命周期回調(初始化或者銷毀)方法之前就調用這個方法。換言之,在程序中使用BeanFactory.getBean(String beanName)之前,Bean的名字就已經設定好了。
BeanFactoryAware接口: 讓Bean獲取配置他們的BeanFactory的引用。可以用這個方式來獲取其它Bean,只需在Spring配置文件中配置一個普通的Bean就可以
BeanPostProcessor接口:
參考:https://blog.csdn.net/wang704987562/article/details/80716267
Spring提供了一個BeanPostProcessor接口,這個接口的作用在於對於新構造的實例可以做一些自定義的修改。比如如何構造、屬性值的修改、構造器的選擇。
如果想改變Spring容器中bean的一些屬性或者行為,可以通過自定義類實現BeanPostProcessor接口實現。
總結:
1.postProcessBeforeInitialization方法的作用在於目標對象實例化之後,初始化之前調用,默認返回原始對象,也可以返回一個包裝實例;
如果返回null,接下來的BeanPostProcessors都不會執行
2.postProcessAfterInitialization方法的作用在於目標對象實例化之後,初始化之後調用,默認返回原始對象,也可以返回一個包裝實例;
如果返回null,接下來的BeanPostProcessors都不會執行
3.初始化(Initialization):表示生成對象,未設置屬性;初始化之前表示bean的初始化回調之前,如InitializingBean接口的afterPropertiesSet方法或者自定義的init-method方法。
https://www.cnblogs.com/V1haoge/p/6106456.html
最後的總結:圖片很清楚,bean--實例化-->初始化-->使用-->銷毀。
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------、
接下來如果各位大佬想繼續深挖,參考一下這篇文章:
---------------------
參考:https://blog.csdn.net/u010634066/article/details/80321854
https://cloud.tencent.com/developer/article/1409273
https://blog.csdn.net/u010634066/article/details/80289441
Spring對對象的可擴展性主要就是依靠InstantiationAwareBeanPostProcessor和BeanPostProcessor來實現的。
- InstantiationAwareBeanPostProcessor 主要是作用於實例化階段。
- BeanPostProcessor 主要作用與 初始化階段。
InstantiationAwareBeanPostProcessor接口繼承BeanPostProcessor接口,它內部提供了3個方法,再加上BeanPostProcessor接口內部的2個方法,所以實現這個接口需要實現5個方法。
InstantiationAwareBeanPostProcessor接口的主要作用在於目標對象的實例化過程中需要處理的事情,包括實例化對象的前後過程以及實例的屬性設置。
InstantiationAwareBeanPostProcessor接口的源代碼:
1 package org.springframework.beans.factory.config; 2 public interface InstantiationAwareBeanPostProcessor extends BeanPostProcessor { 3 4 Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException; 5 6 boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException; 7 8 PropertyValues postProcessPropertyValues( 9 PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeansException; 10 11 }
從源碼中我們可以獲知的信息是該接口除了具有父接口中的兩個方法以外還自己額外定義了三個方法。所以該接口一共定義了5個方法,這5個方法的作用分別是:
註意實例化與初始化兩個單詞不同
Instantiation |
表示實例化,對象還未生成 |
Initialization |
表示初始化,對象已經生成 |
方法 |
描述 |
---|---|
postProcessBeforeInitialization |
BeanPostProcessor接口中的方法,在Bean的自定義初始化方法之前執行 |
postProcessAfterInitialization |
BeanPostProcessor接口中的方法 在Bean的自定義初始化方法執行完成之後執行 |
postProcessBeforeInstantiation |
自身方法,是最先執行的方法,它在目標對象實例化之前調用,該方法的返回值類型是Object,我們可以返回任何類型的值。由於這個時候目標對象還未實例化,所以這個返回值可以用來代替原本該生成的目標對象的實例(比如代理對象)。如果該方法的返回值代替原本該生成的目標對象,後續只有postProcessAfterInitialization方法會調用,其它方法不再調用;否則按照正常的流程走 |
postProcessAfterInstantiation |
在目標對象實例化之後調用,這個時候對象已經被實例化,但是該實例的屬性還未被設置,都是null。因為它的返回值是決定要不要調用postProcessPropertyValues方法的其中一個因素(因為還有一個因素是mbd.getDependencyCheck());如果該方法返回false,並且不需要check,那麽postProcessPropertyValues就會被忽略不執行;如果返回true,postProcessPropertyValues就會被執行 |
postProcessPropertyValues |
對屬性值進行修改,如果postProcessAfterInstantiation方法返回false,該方法可能不會被調用。可以在該方法內對屬性值進行修改 |
調用方法順序
1. postProcessBeforeInstantiation方法
(代碼示例https://cloud.tencent.com/developer/article/1409273)就不粘貼了 ,但是大家一定要先閱讀代碼,再看總結。
a. 返回的結果如果為null,後面的方法都正常執行了後面均正常執行。
b.但是如果該方法返回了實例對象
postProcessBeforeInstantiation方法返回實例對象後跳過了對象的初始化操作,直接執行了postProcessAfterInitialization(該方法在自定義初始化方法執行完成之後執行),跳過了postProcessAfterInstantiation,postProcessPropertyValues以及自定義的初始化方法
2. postProcessAfterInstantiation方法
postProcessAfterInstantiation返回值要註意,因為它的返回值是決定要不要調用postProcessPropertyValues方法的其中一個因素
(因為還有一個因素是mbd.getDependencyCheck())---->如果該方法返回false,並且不需要check,那麽postProcessPropertyValues就會被忽略不執行;如果返true,postProcessPropertyValues就會被執行
3.postProcessPropertyValues方法
對屬性值進行修改
總結:
1.InstantiationAwareBeanPostProcessor接口繼承BeanPostProcessor接口,它內部提供了3個方法,再加上BeanPostProcessor接口內部的2個方法,所以實現這個接口需要實現5個方法。InstantiationAwareBeanPostProcessor接口的主要作用在於目標對象的實例化過程中需要處理的事情,包括實例化對象的前後過程以及實例的屬性設置
2.postProcessBeforeInstantiation方法是最先執行的方法,它在目標對象實例化之前調用,該方法的返回值類型是Object,我們可以返回任何類型的值。由於這個時候目標對象還未實例化,所以這個返回值可以用來代替原本該生成的目標對象的實例(比如代理對象)。如果該方法的返回值代替原本該生成的目標對象,後續只有postProcessAfterInitialization方法會調用,其它方法不再調用;否則按照正常的流程走
3. postProcessAfterInstantiation方法在目標對象實例化之後調用,這個時候對象已經被實例化,但是該實例的屬性還未被設置,都是null。因為它的返回值是決定要不要調用postProcessPropertyValues方法的其中一個因素(因為還有一個因素是mbd.getDependencyCheck());如果該方法返回false,並且不需要check,那麽postProcessPropertyValues就會被忽略不執行;如果返回true, postProcessPropertyValues就會被執行
4.postProcessPropertyValues方法對屬性值進行修改(這個時候屬性值還未被設置,但是我們可以修改原本該設置進去的屬性值)。如果postProcessAfterInstantiation方法返回false,該方法可能不會被調用。可以在該方法內對屬性值進行修改
5.父接口BeanPostProcessor的2個方法postProcessBeforeInitialization和postProcessAfterInitialization都是在目標對象被實例化之後,並且屬性也被設置之後調用的
spring-bean的生命周期