淺嘗Spring註解開發_Bean生命周期及執行過程
Spring註解開發
淺嘗Spring註解開發,基於Spring 4.3.12
包含Bean生命周期、自定義初始化方法、Debug BeanPostProcessor執行過程及在Spring底層中的應用
淺嘗Spring註解開發_自定義註冊組件、屬性賦值、自動裝配
淺嘗Spring註解開發_Bean生命周期及執行過程
Bean生命周期
了解Bean的生命周期,就可以在Bean聲明周期的不同階段進行自定義的操作,滿足更複雜的需求。簡單的將Bean生命周期分為三個階段:Bean創建、初始化、銷毀
- 對象創建:單實例在容器啟動的時候創建對象,多實例在每次獲取的時候創建對象
- 初始化之前:BeanPostProcessor.postProcessBeforeInitialization()
- 初始化:對象創建完成,並賦值好,調用初始化方法
- 初始化之後:BeanPostProcessor.postProcessAfterInitialization()
- [容器創建完成]
- 銷毀:單實例在容器關閉的時候銷毀,多實例容器不會管理這個bean,容器不會調用銷毀方法
現在可以通過下面方法在初始化和銷毀時自定義初始化方法來干涉Bean創建過程。
- @Bean()註解參數
- InitializingBean、DisposableBean接口
- @PostConstruct、@PreDestroy註解
- BeanPostProcessor接口
1.@Bean生命周期
通過@Bean指定init-method和destroy-method的初始化方法
-
先自定義Bean初始化和銷毀方法
@Component public class Car { public Car(){ System.out.println("car constructor..."); } //現在只是普通方法 public void init(){ System.out.println("car ... init..."); } //現在只是普通方法 public void detory(){ System.out.println("car ... destory..."); } }
-
配置進容器
- 通過@Bean註解,在@Bean註冊進容器時指定自定義方法
@Configuration public class MainConfigOfLifeCycle { //@Scope("prototype")多實例,不管銷毀 //指定用於初始化和銷毀的方法 @Bean(initMethod="init",destroyMethod="destory") public Car car(){ return new Car(); } }
-
測試
public class IOCTest_LifeCycle { @Test public void test01(){ //1、創建ioc容器 AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfigOfLifeCycle.class); System.out.println("容器創建完成..."); //applicationContext.getBean("car"); //關閉容器 applicationContext.close(); } }
輸出
//先創建對象 car constructor... //再自定義初始化方法 car ... init... //創建完成 容器創建完成... //關閉時自定義銷毀方法 car ... destory...
2.InitializingBean,DisposableBean生命周期
接口,需實現,通過讓Bean實現InitializingBean(定義初始化邏輯),DisposableBean(定義銷毀邏輯);
-
實現接口,自定義初始化Bean
public class Cat implements InitializingBean,DisposableBean { public Cat(){ System.out.println("cat constructor..."); } //定義銷毀邏輯 @Override public void destroy() throws Exception { // TODO Auto-generated method stub System.out.println("cat...destroy..."); } //定義初始化邏輯 @Override public void afterPropertiesSet() throws Exception { // TODO Auto-generated method stub System.out.println("cat...afterPropertiesSet..."); } }
-
配置進容器
- 在@Configuration配置類中使用@Bean
- 或在Bean類上使用@Component然後再配置類上使用@ComponentScan
//配置組件 @Component public class Cat implements InitializingBean,DisposableBean { //... }
//掃描進容器 @ComponentScan("com.xxx.bean") @Configuration public class MainConfigOfLifeCycle { //... }
-
測試
public class IOCTest_LifeCycle { @Test public void test01(){ //1、創建ioc容器 AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfigOfLifeCycle.class); System.out.println("容器創建完成..."); //applicationContext.getBean("car"); //關閉容器 applicationContext.close(); } }
輸出
//注意順序,每個Bean先構造並初始化,然後才進行下一個Bean,關閉時從內向外 (貓)cat constructor... (貓)cat...afterPropertiesSet... (車)car constructor... (車)car ... init... //創建完成 容器創建完成... //關閉時銷毀 (車)car ... destory... (貓)cat...destroy...
3.@PostConstruct生命周期
可以使用JSR250;
-
@PostConstruct:在bean創建完成並且屬性賦值完成之後,來執行初始化方法
-
@PreDestroy:在容器銷毀bean之前通知我們進行清理工作
-
標註註解,自定義初始化Bean
public class Dog { public Dog(){ System.out.println("dog constructor..."); } //對象創建並賦值之後調用 @PostConstruct public void init(){ System.out.println("Dog....@PostConstruct..."); } //容器移除對象之前 @PreDestroy public void detory(){ System.out.println("Dog....@PreDestroy..."); } }
-
配置進容器
- 在@Configuration配置類中使用@Bean
- 或在Bean類上使用@Component然後再配置類上使用@ComponentScan
@Component public class Dog { //... }
//掃描進容器 @ComponentScan("com.xxx.bean") @Configuration public class MainConfigOfLifeCycle { //... }
-
測試
public class IOCTest_LifeCycle { @Test public void test01(){ //1、創建ioc容器 AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfigOfLifeCycle.class); System.out.println("容器創建完成..."); //applicationContext.getBean("car"); //關閉容器 applicationContext.close(); } }
輸出
//注意順序,每個Bean先構造並初始化,然後才進行下一個Bean,關閉時從內向外 (貓)cat constructor... (貓)cat...afterPropertiesSet... (狗)dog constructor... (狗)Dog....@PostConstruct... (車)car constructor... (車)car ... init... //創建完成 容器創建完成... //關閉時銷毀 (車)car ... destory... (狗)Dog....@PreDestroy... (貓)cat...destroy...
4.BeanPostProcessor
postProcessBeforeInitialization:在創建Bean實例之後,在自定義初始化之前進行調用
postProcessAfterInitialization:在自定義初始化之後進行調用
BeanPostProcessor接口:bean的後置處理器,需實現,在bean初始化前後進行一些處理工作
-
postProcessBeforeInitialization:在(自定義初始化,如InitializingBean[afterPropertiesSet]、init-method等,就是上面那些自定義初始化方法)初始化之前工作(創建Bean實例之後,在自定義初始化之前)
-
postProcessAfterInitialization:在(自定義)初始化之後工作
-
實現後置處理器接口
public class MyBeanPostProcessor implements BeanPostProcessor { //初始化前置方法 //bean:新創建的實例,還未初始化 //beanName:未初始化的Bean名字 @Override public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { // TODO Auto-generated method stub System.out.println("postProcessBeforeInitialization..."+beanName+"=>"+bean); return bean; } //初始化後置方法 @Override public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { // TODO Auto-generated method stub System.out.println("postProcessAfterInitialization..."+beanName+"=>"+bean); return bean; } }
-
配置進容器
- 在@Configuration配置類中使用@Bean
- 或在Bean類上使用@Component然後再配置類上使用@ComponentScan
@Component public class MyBeanPostProcessor implements BeanPostProcessor { //... }
//掃描進容器 @ComponentScan("com.xxx.bean") @Configuration public class MainConfigOfLifeCycle { //... }
-
測試
- 這次沒有新增的Bean,只配置了一個後置處理器,
- 這個後置處理器會對容器中的Bean起作用,包括上面三種自定義初始化Bean
public class IOCTest_LifeCycle { @Test public void test01(){ //1、創建ioc容器 AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfigOfLifeCycle.class); System.out.println("容器創建完成..."); //applicationContext.getBean("car"); //關閉容器 applicationContext.close(); } }
輸出
//對於每一個Bean都要執行一遍 //1.創建 //2.BeanPostProcessor.postProcessBeforeInitialization() //3.初始化:對象創建完成,並賦值好,調用初始化方法... //4.BeanPostProcessor.postProcessAfterInitialization() //5.銷毀 //以其中一個Bean為例: //構造對象 cat constructor... //初始化之前 postProcessBeforeInitialization...cat=>com.xxx.bean.Cat@7d68ef40 //使用InitializingBean自定義初始化邏輯 cat...afterPropertiesSet... //初始化之後 postProcessAfterInitialization...cat=>com.xxx.bean.Cat@7d68ef40 //創建完成 容器創建完成... //關閉時銷毀 cat ... destroy...
BeanPostProcessor原理
bean賦值,注入其他組件,@Autowired,生命周期註解功能,@Async,xxxBeanPostProcessor都通過BeanPostProcessor實現
主要方法
populateBean(beanName, mbd, instanceWrapper):給bean進行屬性賦值
initializeBean:初始化Bean
{
applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);初始化前應用後置處理器
invokeInitMethods(beanName, wrappedBean, mbd);執行自定義初始化
applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);初始化後應用後置處理器
}
遍歷得到容器中所有的BeanPostProcessor;挨個執行beforeInitialization,
一但返回null,跳出for循環
執行過程
了解BeanPostProcessor的執行過程,從AnnotationConfigApplicationContext開始Debug
public class IOCTest_LifeCycle {
@Test
public void test01(){
//1、創建ioc容器
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfigOfLifeCycle.class);
System.out.println("容器創建完成...");
//applicationContext.getBean("car");
//關閉容器
applicationContext.close();
}
}
- 先從創建ioc容器開始,進入
AnnotationConfigApplicationContext()
構造方法,執行裏面的refresh()
方法刷新容器refresh()
方法裏面有一個finishBeanFactoryInitialization(beanFactory)
初始化所有剩餘的單實例對象,進入這個方法
- 這個方法最後一步有一個
beanFactory.preInstantiateSingletons()
初始化所有單實例Bean,進入這個方法- 觸發所有非惰性單例bean的初始化
- 裏面調用
getBean(beanName)
, - 進入
getBean(beanName)
裏面再調用doGetBean(name,null,null,false)
- 進入
doGetBean(name,null,null,false)
裏面有getSingleton(beanName,new ObjectFactory(){singletonFactory.getObject()})
通過匿名內部類調用getObject()
- 此時通過匿名類
getObject()
進入下一個調用棧AbstractBeanFactory$1.getObject()
,如果是單例,調用createBean(beanName,mbd,args)
- 進入
createBean(beanName,mbd,args)
調用doCreateBean(beanName,mbd,args)
創建一個實例,過程如下- 進入
doCreateBean(beanName,mbd,args)
,裏面調用一個initializeBean(beanName,exposedObject,mbd)
初始化方法,這個方法裏面就是調用的後置處理器 - 在這個方法上面有
populateBean(beanName,mbd,instanceWrapper)
方法,這個方法為Bean屬性賦值 - 進入
initializeBean(beanName,exposedObject,mbd)
,下面有一個invokeInitMethods(beanName,wrappedBean,mbd)
執行初始化方法(就是上面的自定義初始化InitializingBean[afterPropertiesSet]、init-method) - 在
invokeInitMethods(beanName,wrappedBean,mbd)[在初始化之前應用 BeanPost 處理器]
上面有一個applyBeanPostProcessorsBeforeInitialization(wrappedBean,beanName)
下面有一個applyBeanPostProcessorsAfterInitialization(wrappedBean,beanName)[在初始化之後應用 BeanPost 處理器]
,作用是在初始化之前應用所有的BeanPostProcessors
在初始化之後應用所有的BeanPostProcessors
- 進入
- 進入
applyBeanPostProcessorsBeforeInitialization(wrappedBean,beanName)
- 裏面有
getBeanPostProcessors()
找到所有BeanPostProcessors
遍歷,包括Spring系統的BeanPostProcessor
如ApplicationContextAwareProcessor
、ConfigurationClassPostProcessor
等,然後才是自定義的MyBeanPostProcessor
,依次執行beanProcessor.postProcessBeforeInitialization()
- 如果有執行返回null,就結束遍歷,返回null,後面的處理器就不執行了(不應用後續的
BeanPostProcessors
了)
- 裏面有
調用棧
-
獲取單例
-
創建實例Bean
-
給Bean屬性賦值和初始化Bean
完整流程
Spring底層對 BeanPostProcessor 的使用;
- 由上圖可以看到,Spring中的BeanPostProcessor在實例化過程處於的位置,BeanPostProcessor接口有兩個方法需要實現:postProcessBeforeInitialization和postProcessAfterInitialization
- 前者在實例化及依賴注入完成後、在任何初始化代碼(比如配置文件中的init-method)調用之前調用;後者在初始化代碼調用之後調用。
BeanPostProcessor在Spring底層的使用
許多註解底層都是基於BeanPostProcessor
BeanPostProcessor接口實現類
向組件中注入IoC容器
在Bean創建過程中,初始化之前,判斷是否實現了某Aware接口,如果實現了,就向Bean中注入ApplicationContext容器
-
向Bean中注入IoC容器
-
實現ApplicationContextAware接口,聲明屬性,賦值,就可以在組件中使用Ioc容器
@Component public class Dog implements ApplicationContextAware { //聲明IoC容器 private ApplicationContext applicationContext; public Dog(){ System.out.println("dog constructor..."); } //對象創建並賦值之後調用 @PostConstruct public void init(){ System.out.println("Dog....@PostConstruct..."); } //容器移除對象之前 @PreDestroy public void detory(){ System.out.println("Dog....@PreDestroy..."); } //把applicationContext IoC容器賦值給屬性 @Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { // TODO Auto-generated method stub this.applicationContext = applicationContext; } }
-
-
原理是通過
ApplicationContextAwareProcessor
實現-
ApplicationContextAwareProcessor
實現了BeanPostProcessor
接口 -
在
postProcessBeforeInitialization()
方法中- 在Bean初始化之前,判斷Bean是否實現了
ApplicationContextAware
接口,或其他Aware接口 - 如果實現了,就調用
invokeAwareInterfaces(bean)
給Bean注入值 - 判斷Bean是什麼類型Aware,將Bean轉成對應類型調用
((ApplicationContextAware)bean).setApplicationContext(this.applicationContext)
注入IoC容器 - 於是就到了上面實現的接口的未實現方法中
- 在Bean初始化之前,判斷Bean是否實現了
-
數據校驗
BeanValidationPostProcessor
也實現了BeanPostProcessor
接口- 在Bean創建完賦值後,同樣調用
postProcessBeforeInitialization()
方法,進行數據校驗postProcessBeforeInitialization(){doValidate(bean)}
postProcessAfterInitialization(){doValidate(bean)}
自定義初始化註解
- Bean初始化有一種方法是使用
@PostConstruct
註解,也是通過BeanPostProcessor
實現 InitDestroyAnnotationBeanPostProcessor
處理@PostConstruct
和@PreDestroy
註解- 在
postProcessBeforeInitialization()
中找到Bean的生命周期註解所標註的方法,如initMethods、destroyMethods
- 找到之後就執行註解標註的初始化方法
metatata.invokeInitMethods(bean,beanName)
和element.invoke(target)
,利用反射執行。
- 在
自動注入註解@Autowired
- 為什麼@Autowired能夠自動注入值,是通過這個
AutowiredAnnotationBeanPostProcessor
實現BeanPostProcessors
接口 - 在對象創建完之後,處理標註
@Autowired
標註的所有屬性進行注入值