Spring註解開發_Bean生命週期及執行過程
淺嘗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
標註的所有屬性進行注入值