五)Bean 的生命週期,創建---初始化---銷燬的過程
目錄
三,實現 InitializingBean 接口的 afterPropertiesSet()方法,當beanFactory 創建好對象,且把bean所有屬性設置好之後,相當於初始化方法。
實現 DisposableBean 的destory(),方法 當bean銷燬時,會把單例bean 進行銷燬
四, 可以使用JSR250規則定義的(java規範)兩個註解來實現,JDK自帶
五,Bean 的後置處理器,在 Bean 初始化之前調用進行攔截,在 bean 初始化前後進行一些處理工作,使用BeanPostProcessors 控制 Bean的生命週期。
一 , 指定初始化方法 init-method 方法
- 單實例 Bean,可以正常調用初始化和銷燬方法
- 多實例的 Bean,容器只負責初始化,但不會管理bean,容器關閉時不會調用銷燬方法
示例代碼:===》 項目 源碼 ====》 Cap8包: xml 方式 指定
<!--創建Bike 類 bike 實例, 自定義初始化方法 init(),自定義銷燬方法 destory()-->
<bean id="bike" class="com.enjoy.Cap8.bean.Bike" init-method="init" destroy-method="destory"></bean>
註解實現===》項目 源碼 ====》 Cap8包: (單實例模式下在容器創建之前實例化 Bean )
//自定義初始化方法, 銷燬方法
@Bean(initMethod = "init",destroyMethod = "destory")
public Bike bike(){
System.out.println("公交車到站了====》註冊到bean");
return new Bike();
}
public class Bike {
public Bike(){
System.out.println("有一位乘客上車了=====>調類的構造方法");
}
//自定義bean 初始化方法
public void init(){
System.out.println("車啓動了====》 bean初始化方法");
}
//自定義bean 銷燬方法
public void destory(){
System.out.println("車爆炸了====》bean銷燬方法,關閉容器");
}
}
測試結果:
@Test
public static void main(String[] args){
//創建上下文對象
AnnotationConfigApplicationContext app = new AnnotationConfigApplicationContext(Cap8MainConfigOfLifeCycle.class);
app.close();
}
註解實現===》項目 源碼 ====》 Cap8包(多實例,容器在創建之前 不會去實例化 Bean ,只有當 getBean() 的時候纔會去 創建實例 )
//自定義初始化方法, 銷燬方法,多實例模式下
@Scope("prototype")
@Bean(initMethod = "init",destroyMethod = "destory")
public Bike bike(){
System.out.println("公交車到站了====》註冊到bean");
return new Bike();
}
Bike 與上面一致 測試 :
@Test
public static void main(String[] args){
//創建上下文對象
AnnotationConfigApplicationContext app = new AnnotationConfigApplicationContext(Cap8MainConfigOfLifeCycle.class);
System.out.println("容器創建完成");
//app.getBean("bike");
app.close();
}
當我沒有去getBean 的時候, Bean 並沒有實例化
@Test
public static void main(String[] args){
//創建上下文對象
AnnotationConfigApplicationContext app = new AnnotationConfigApplicationContext(Cap8MainConfigOfLifeCycle.class);
System.out.println("容器創建完成");
app.getBean("bike");
app.close();
}
結果顯而易見, 在容器創建完成之後getBean() 纔會去 創建 Bean 的實例 ,並且沒有調用銷燬方法
實現原理: 源碼跟蹤
二 ,指定銷燬 destory-method 方法
示例代碼:見 5.1 代碼 ====》項目源碼 Cap8;
三,實現 InitializingBean 接口的 afterPropertiesSet()方法,當beanFactory 創建好對象,且把bean所有屬性設置好之後,相當於初始化方法。
實現 DisposableBean 的destory(),方法 當bean銷燬時,會把單例bean 進行銷燬
示例源碼: ====》項目源碼 Cap8;
// 將 類註解爲註解,讓容器掃描注入bean
@Component
public class Volkswagen implements InitializingBean, DisposableBean {
public Volkswagen(){
System.out.println("構造方法, 大衆cc,買到手");
}
//實現 DisposableBean 接口, destroy 銷燬方法
@Override
public void destroy() throws Exception {
System.out.println("大衆cc,沒了。。===》 容器銷燬");
}
//實現 InitializingBean 接口, afterPropertiesSet() 初始化方法
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("大衆cc,最愛。。===》 bean初始化");
}
}
在配置類 增加掃描註解 將 該包下面的掃描到容器中
@Configuration
//掃描包下所有組件,並注入bean 到容器
@ComponentScan("com.enjoy.Cap8.bean")
public class Cap8MainConfigOfLifeCycle {
//自定義初始化方法, 銷燬方法,多實例模式下
@Scope("prototype")
@Bean(initMethod = "init",destroyMethod = "destory")
public Bike bike(){
System.out.println("公交車到站了====》註冊到bean");
return new Bike();
}
}
測試:
@Test
public static void main(String[] args){
//創建上下文對象
AnnotationConfigApplicationContext app = new AnnotationConfigApplicationContext(Cap8MainConfigOfLifeCycle.class);
System.out.println("容器創建完成");
//System.out.println(app.getBean("bike"));
System.out.println(app.getBean("volkswagen"));
app.close();
}
四, 可以使用JSR250規則定義的(java規範)兩個註解來實現,JDK自帶
- @PostConstruct : 在Bean 創建完成,且shu屬於賦值完成後進行初始化,屬於JDK規範的註解
- @PreDestroy : 在Bean 將被移除之前進行通知,在容器銷燬之前進行清理工作
示例源碼: ====》項目源碼 Cap8;
@Component
public class Benz {
public Benz(){
System.out.println("構造方法,買了一輛奔馳");
}
//使用JSR250規則定義 JDK 自帶註解 初始化 bean
@PostConstruct
public void init(){
System.out.println("奔馳漏油了 ====》初始bean");
}
//使用JSR250規則定義 JDK 自帶註解 容器銷燬
@PreDestroy
public void destroy(){
System.out.println("奔馳爆炸了 ====》容器銷燬");
}
}
在配置類 增加掃描註解 將 該包下面的掃描到容器中
@Configuration
//掃描包下所有組件,並注入bean 到容器
@ComponentScan("com.enjoy.Cap8.bean")
public class Cap8MainConfigOfLifeCycle {
//自定義初始化方法, 銷燬方法,多實例模式下
@Scope("prototype")
@Bean(initMethod = "init",destroyMethod = "destory")
public Bike bike(){
System.out.println("公交車到站了====》註冊到bean");
return new Bike();
}
}
測試
@Test
public static void main(String[] args){
//創建上下文對象
AnnotationConfigApplicationContext app = new AnnotationConfigApplicationContext(Cap8MainConfigOfLifeCycle.class);
System.out.println("容器創建完成");
//System.out.println(app.getBean("bike"));
//System.out.println(app.getBean("volkswagen"));
System.out.println(app.getBean("benz"));
app.close();
}
五,Bean 的後置處理器,在 Bean 初始化之前調用進行攔截,在 bean 初始化前後進行一些處理工作,使用BeanPostProcessors 控制 Bean的生命週期。
實現 BeanPostProcessors兩個接口即可:
- postProcessBeforelnitialization() 在Bean 初始化之前 進行攔截 增強
- postProcessAfterInitalization() 在Bean 初始化之後 進行攔截 增強
Spring 底層對 BeanPostProcessor 的使用,包括 bean 的賦值,注入其他組件,生命週期註解功能等。 如:
- ApplicationContextAwareProcesspor 接口 這個後置處理器其實就是判斷我們的 bean 有沒有實現 ApplicationContextAware 這個接口 ,並處理相應的邏輯,
- BeanValidationPostProcess 接口 數據校驗
- InitDestroyAnnotationBeanPostProcessor 接口 此處理器 是用來處理 上述 5.4@PostConstruct @PreDestroy 讓 容器 找到 init 方法 和 destroy 方法
示例源碼: ====》項目源碼 Cap8;
實現 BeanPostProcessors 接口, 裏面的兩個方法
@Component
public class Bmw implements BeanPostProcessor {
/**Aop 在初始化bean 攔截 進行增強 做一些操作,如 任何bean 初始化回調或自定義初始化方法之前,
*將此BeanPostProcessor應用於給定的新bean實例 bean已經填充了屬性值。 返回的bean實例可能是原始實例的包裝器
**/
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println("postProcessBeforeInitialization=====>"+bean+"===>"+beanName);
return bean;
}
/**Aop 在初始化bean 攔截 進行增強 做一些操作,如 一般的Aop 事務 在事件之後 commit,
*在bean初始完後 攔截 增強 對於FactoryBean,將爲FactoryBean 實例和FactoryBean創建的對象調用此回調。
* 處理器可以通過相應的檢查來決定是應用於FactoryBean還是應用於創建的對象。 與所有其他BeanPostProcessor回調相比
**/
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println("postProcessAfterInitialization=====>"+bean+"===>"+beanName);
return bean;
}
}
配置類 ; 爲了便於觀察 當前 只是 掃描到 benz 這個類
@Configuration
//掃描包下所有組件,並注入bean 到容器
@ComponentScan("com.enjoy.Cap8.bean")
public class Cap8MainConfigOfLifeCycle {
//自定義初始化方法, 銷燬方法,多實例模式下
//@Scope("prototype")
//@Bean(initMethod = "init",destroyMethod = "destory")
public Bike bike(){
System.out.println("公交車到站了====》註冊到bean");
return new Bike();
}
}
測試:
@Test
public static void main(String[] args){
//創建上下文對象
AnnotationConfigApplicationContext app = new AnnotationConfigApplicationContext(Cap8MainConfigOfLifeCycle.class);
System.out.println("容器創建完成");
//System.out.println(app.getBean("bike"));
//System.out.println(app.getBean("volkswagen"));
System.out.println(app.getBean("benz"));
app.close();
}
觀察結果
六 :項目Demo
Spring源碼深度解析,(附代碼示例 碼雲地址: https://gitee.com/Crazycw/SpringCode.git)
參考資料: https://docs.spring.io/spring/docs/4.3.18.BUILD-SNAPSHOT/spring-framework-reference/htmlsingle/
請看下篇: Spring源碼深度解析,初始Spring源碼(六)(附代碼示例:)