二.Aware介面
2.1 BeanNameAware
2.2 BeanFactoryAware
2.4 Aware各介面的執行順序
2.4 Aware介面總結
六.DestructionAwareBeanPostProcessor介面
九.生命週期大雜燴
9.1 實現多介面的Student類
9.3 DestructionAwareBeanPostPrecessor介面
9.4 配置xml檔案
9.5 測試程式碼
9.6 輸出結果
十.總結
Spring Bean的生命週期是一個老生常談的問題了,網上一搜一大把,無非就是畫一幅流程圖(比如下面這幅圖),然後用語言介紹建立bean後執行各Aware介面,然後BeanPostProcessor.....最終Bean建立成功了,就可以使用這個Bean了,然後在容器銷燬的時候,又會執行一些操作。
其實對於上面的提到的流程圖,注意上面的圖只是Spring Bean的大概流程(省略了一部分),主要涉及到了5個介面,分別是XxxAware、BeanPostProcessor、InitiailizingBean、Destruction、DisposableBean介面,本文將會對這幾個介面,以及init-method、destroy-method做相關的使用介紹,在明白怎麼使用後,再把他們串起來,這樣的話,對於Spring Bean的生命週期就差不多知道咋回事了,而不用死記硬背。
一. xml方式配置Bean
在說Aware、BeanPostProcessor、InitiailizingBean、Destruction、DisposableBean這些介面前,先簡單回顧一下使用xml配置並獲取一個Student類的bean過程,後面介紹各個介面的使用方式時時,也是按照這個形式;
1.1 建立Student類
平淡無奇的Student類:
package cn.ganlixin.entity; import lombok.Data; import lombok.extern.slf4j.Slf4j; @Data @Slf4j public class Student { private Integer id; private String name; }
1.2 建立配置檔案
平淡無奇的applicationContext.xml配置檔案,建立一個student bean,利用setter方式設定初始值:
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <bean class="cn.ganlixin.entity.Student" id="student"> <property name="id" value="99"/> <property name="name" value="張三"/> </bean> </beans>
1.3 測試
建立一個Main類,用於測試
package cn.ganlixin; import cn.ganlixin.entity.Student; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.BeanFactory; import org.springframework.beans.factory.xml.XmlBeanFactory; import org.springframework.core.io.ClassPathResource; @Slf4j public class Test { public static void main(String[] args) { BeanFactory beanFactory = new XmlBeanFactory(new ClassPathResource("applicationContext.xml")); Student student = beanFactory.getBean("student", Student.class); log.info("測試程式獲取到的student bean:{}", student); } }
下面是執行程式的輸出,可以看到和預期相符,建立一個Student的bean,id和name預設值為99、張三;
INFO [main] cn.ganlixin.Test - 測試程式獲取到的student bean:Student(id=99, name=張三)
二.Aware介面
Aware介面有很多實現類,本文只介紹BeanNameAware、BeanFactoryAware、ApplicationContextAware,關係如下:
2.1 BeanNameAware
建立一個Student類,讓該類實現BeanNameAware介面,並且重寫setBeanName方法
@Data @Slf4j public class Student implements BeanNameAware { private Integer id; private String name; /** * 實現了BeanNameAware介面後,需重寫setBeanName方法,接收的引數就是bean的id * * @param s bean的id */ @Override public void setBeanName(String s) { log.info("beanName:{}, student bean:{}", s, this); this.id = 100; log.info("將beanName:{}的id改為100", s); } }
配置檔案和測試程式都不改變,執行測試程式,輸出內容如下:
INFO [main] cn.ganlixin.entity.Student - beanName:student, student bean:Student(id=99, name=張三) INFO [main] cn.ganlixin.entity.Student - 將beanName:student的id改為100 INFO [main] cn.ganlixin.Test - 測試程式獲取到的student bean:Student(id=100, name=張三)
可以看到,實現BeanNameAware介面後,重寫setBeanName的方法中,獲取到的student bean,是已經初始化的bean(屬性都已經有值了),並且setBeanName方法中可以對當前的bean進行各種操作,包括修改bean的某些屬性,最後獲取到的bean是已經修改後的bean。
這裡只是簡單介紹了一下BeanNameAware介面的用法,使用BeanNameAware介面,可以對當前Bean進行操作。
2.2 BeanFactoryAware
建立Student類,實現BeanFactoryAware介面,並且重寫setBeanFactory方法
@Data @Slf4j public class Student implements BeanFactoryAware { private Integer id; private String name; /** * 實現BeanFactoryAware介面後,需重寫setBeanFactroy方法 * * @param beanFactory 建立該bean的beanFactory */ @Override public void setBeanFactory(BeanFactory beanFactory) throws BeansException { // 可以在setBeanFactory方法中獲取、修改beanFactory中的所有bean log.info("student this bean:{}", this); Student student = beanFactory.getBean("student", Student.class); log.info("通過beanFactory獲取student bean:{}", student); // 將name設定為李四 this.name = "李四"; } }
執行輸出如下:
INFO [main] cn.ganlixin.entity.Student - student this bean:Student(id=99, name=張三) INFO [main] cn.ganlixin.entity.Student - 通過beanFactory獲取student bean:Student(id=99, name=張三) INFO [main] cn.ganlixin.Test - 測試程式獲取到的student bean:Student(id=99, name=李四)
通過上面的程式碼輸出結果可以看出,實現BeanFactoryAware介面後,可以在setBeanFactory方法中操作BeanFactory的所有bean,操作的範圍要比BeanNameAware要大。
2.3 ApplicationContextAware
ApplicationContext,有多種稱呼,比如“應用容器”、“環境”、“上線文”...
建立Student類,實現ApplicationContextAware介面,並且重寫setApplicationContext介面:
@Data @Slf4j public class Student implements ApplicationContextAware { private Integer id; private String name; /** * 實現ApplicationContextAware介面後,徐重寫setApplicationContext方法 * * @param applicationContext 該bean所在的上下文(applicationContext、容器) */ @Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { log.info("Student this:{}", this); final Student student = applicationContext.getBean("student", Student.class); final Environment environment = applicationContext.getEnvironment(); log.info("student bean:{}", student); log.info("env -> user.dir:{}", environment.getProperty("user.dir")); } }
需要修改一下測試程式,測試程式中載入配置時使用的XmlBeanFactory,而XmlBeanFactory不會回撥ApplicationContextAware介面的setApplicationContext方法,下面使用ClassPathXmlApplicationContext類來載入配置:
@Slf4j public class Test { public static void main(String[] args) { //BeanFactory beanFactory = new XmlBeanFactory(new ClassPathResource("applicationContext.xml")); // 使用ApplicationContext來載入配置 ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml"); Student student = context.getBean("student", Student.class); log.info("測試程式獲取到的student bean:{}", student); } }
執行測試程式:
INFO [main] cn.ganlixin.entity.Student - Student this:Student(id=99, name=張三) INFO [main] cn.ganlixin.entity.Student - student bean:Student(id=99, name=張三) INFO [main] cn.ganlixin.entity.Student - env -> user.dir:/Users/ganlixin/code/java-code-all/spring INFO [main] cn.ganlixin.Test - 測試程式獲取到的student bean:Student(id=99, name=張三)
實現ApplicationContextAware介面後,在setApplicationContext方法中,入參是當前的applicationContext,也就是說,可以在該方法中對Spring容器進行設定,操作的範圍又要比BeanFactoryAware的setBeanFactory要廣得多。
2.4 Aware各介面執行的先後順序
既然有這幾個Aware介面,如果一個類同時實現了這3個介面,那麼執行順序是怎樣的呢?下面就來測試一下。
建立Student類,分別實現BeanNameAware、BeanFactoryAware、ApplicationContextAware介面,並重寫其介面的方法:
@Data @Slf4j public class Student implements BeanNameAware, BeanFactoryAware, ApplicationContextAware { private Integer id; private String name; /** * 實現了BeanNameAware介面後,需重寫setBeanName方法,接收的引數就是bean的id * * @param s bean的id */ @Override public void setBeanName(String s) { log.info("call BeanNameAware.setBeanName()"); } /** * 實現BeanFactoryAware介面後,需重寫setBeanFactroy * * @param beanFactory 建立該bean的bean工廠 */ @Override public void setBeanFactory(BeanFactory beanFactory) throws BeansException { log.info("call BeanFactoryAware.setBeanFactory()"); } /** * 實現ApplicationContextAware介面後,徐重寫setApplicationContext方法 * * @param applicationContext 該bean所在的上下文(applicationContext、容器) */ @Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { log.info("call ApplicationContextAware.setApplicationContext()"); } }
仍舊使用ClassPathXmlApplicationContext類來載入配置,執行輸出結果如下:
INFO [main] cn.ganlixin.entity.Student - call BeanNameAware.setBeanName() INFO [main] cn.ganlixin.entity.Student - call BeanFactoryAware.setBeanFactory() INFO [main] cn.ganlixin.entity.Student - call ApplicationContextAware.setApplicationContext() INFO [main] cn.ganlixin.Test - 測試程式獲取到的student bean:Student(id=99, name=張三)
2.4 Aware介面總結
上面演示了Spring中幾個Aware介面的用法和特點,下面總結一下:
1.實現BeanNameAware介面後,重寫setBeanName方法,可以對單個Bean進行擴充套件修改;
2.實現BeanFactoryAware介面後,重寫setBeanFactory方法,可以對bean工廠中的所有Bean進行擴充套件修改;
3.實現ApplicationContextAware介面後,重寫setApplicationContext方法後,可以對整個容器進行擴充套件修改;
4.這幾個介面的執行順序分別是BeanNameAware->BeanFactoryAware->ApplicationContextAware;
三.BeanPostProcessor介面
BeanPostProcessor和前面的Aware介面有些區別,通過下面的例子就能看出區別在哪裡!
下面舉個例子,建立MyBeanPostProcessor類,實現BeanPostProcessor介面,注意,這裡沒有在Student類上實現BeanPostProcessor介面。
@Slf4j public class MyBeanPostProcessor implements BeanPostProcessor { /** * 實現了BeanPostProcessor介面後,重寫postProcessBeforeInitialization,在各種Aware介面執行完畢後執行該方法 * * @param bean 本次處理的bean * @param beanName 本次處理的beanName(bean id) * @return 返回的是在本方法中處理後的bean */ @Override public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { log.info("MyBeanPostProcessor.postProcessBeforeInitialization, beanName:{}, bean:{}", beanName, bean); return bean; } /** * 實現了BeanPostProcessor介面後,重寫postProcessBeforeInitialization,在initMethod方法執行完畢後執行該方法 * * @param bean 本次處理的bean * @param beanName 本次處理的beanName(bean id) * @return 返回的是在本方法中處理後的bean */ @Override public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { log.info("MyBeanPostProcessor.postProcessAfterInitialization, beanName:{}, bean:{}", beanName, bean); return bean; } }
建立兩個類,分別是Student和User類,其中Use類沒有實現Aware介面,Student類實現了前面提到的3個Aware介面
@Data public class User { private Integer id; private String name; }
@Data @Slf4j public class Student implements BeanNameAware, BeanFactoryAware, ApplicationContextAware { private Integer id; private String name; /** * 實現了BeanNameAware介面後,需重寫setBeanName方法,接收的引數就是bean的id * * @param s bean的id */ @Override public void setBeanName(String s) { log.info("call BeanNameAware.setBeanName()"); } /** * 實現BeanFactoryAware介面後,需重寫setBeanFactroy * * @param beanFactory 建立該bean的bean工廠 */ @Override public void setBeanFactory(BeanFactory beanFactory) throws BeansException { log.info("call BeanFactoryAware.setBeanFactory()"); } /** * 實現ApplicationContextAware介面後,徐重寫setApplicationContext方法 * * @param applicationContext 該bean所在的上下文(applicationContext、容器) */ @Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { log.info("call ApplicationContextAware.setApplicationContext()"); } }
xml配置檔案:
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <bean class="cn.ganlixin.entity.Student" id="student"> <property name="id" value="99"/> <property name="name" value="張三"/> </bean> <bean class="cn.ganlixin.entity.User" id="user"> <property name="id" value="88"/> <property name="name" value="王五"/> </bean> <!-- 將實現了BeanPostProcessor介面的類也宣告為bean --> <bean class="cn.ganlixin.processor.MyBeanPostProcessor"/> </beans>
測試:
INFO [main] cn.ganlixin.entity.Student - call BeanNameAware.setBeanName() INFO [main] cn.ganlixin.entity.Student - call BeanFactoryAware.setBeanFactory() INFO [main] cn.ganlixin.entity.Student - call ApplicationContextAware.setApplicationContext() INFO [main] cn.ganlixin.processor.MyBeanPostProcessor - MyBeanPostProcessor.postProcessBeforeInitialization, beanName:student1, bean:Student(id=99, name=張三) INFO [main] cn.ganlixin.processor.MyBeanPostProcessor - MyBeanPostProcessor.postProcessAfterInitialization, beanName:student1, bean:Student(id=99, name=張三) INFO [main] cn.ganlixin.processor.MyBeanPostProcessor - MyBeanPostProcessor.postProcessBeforeInitialization, beanName:user, bean:User(id=88, name=王五) INFO [main] cn.ganlixin.processor.MyBeanPostProcessor - MyBeanPostProcessor.postProcessAfterInitialization, beanName:user, bean:User(id=88, name=王五) INFO [main] cn.ganlixin.Test - 測試程式獲取到的student bean:Student(id=99, name=張三)
從上面的執行結果可以得出以下結論:
1.因為只有Student實現了Aware介面,所以建立student bean的時候會呼叫對應的Aware介面方法,而User類沒有實現Aware介面,所以並沒有呼叫Aware介面方法;
2.Student和User類都沒有繼承BeanPostProcessor介面,但是在建立student和user bean的時候,都掉用了MyBeanPostProcessor類中的前置和後置處理(繼承自BeanPostProcessor介面);
3.BeanPostProcessor介面的前置和後置處理,是在Aware介面之後呼叫;
4.很重要的一點,需要將BeanPostProcessor介面實現類宣告為bean,使用<bean>配置或者使用@Component註解,不然BeanPostProcessor不起作用。
四.InitializingBean介面
建立Student類,實現InitializingBean介面,然後重寫afterPropertiesSet方法:
@Data @Slf4j public class Student implements InitializingBean { private Integer id; private String name; @Override public void afterPropertiesSet() throws Exception { // 同樣可以在這裡修改bean的屬性值 log.info("InitialingBean.afterPropertiesSet, this:{}", this); } }
修改xml配置檔案,建立student bean,測試:
INFO [main] cn.ganlixin.entity.Student - InitialingBean.afterPropertiesSet, this:Student(id=99, name=張三) INFO [main] cn.ganlixin.Test - 測試程式獲取到的student bean:Student(id=99, name=張三)
五.init-method
建立Student類,增加一個額外的方法display()
@Data @Slf4j public class Student { private Integer id; private String name; public void display() { log.info("Student.display call, this:{}", this); } }
修改配置檔案,在<bean>標籤中增加init-method屬性,值為display,也就是Student的display方法名:
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <bean class="cn.ganlixin.entity.Student" id="student" init-method="display"> <property name="id" value="99"/> <property name="name" value="張三"/> </bean> </beans>
執行測試:
INFO [main] cn.ganlixin.entity.Student - Student.display call, this:Student(id=99, name=張三) INFO [main] cn.ganlixin.Test - 測試程式獲取到的student bean:Student(id=99, name=張三)
上面,輸出了display中的內容,這是在設定bean的時候呼叫的。
六.DestructionAwareBeanPostProcessor介面
DestructionAwareBeanPostProcessor介面,從名稱上可以看出來是DestructionAware + BeanPostProcessor的組合,其實也的確是這樣,但是需要注意的就是,spring並沒有提供DestructionAware介面!!
下面是DestructionAwareBeanPostProcessor介面的定義:
public interface DestructionAwareBeanPostProcessor extends BeanPostProcessor { /** * Destruction執行的操作 * * @param bean 處理的bean * @param beanName bean的名稱 * @throws BeansException */ void postProcessBeforeDestruction(Object bean, String beanName) throws BeansException; /** * 是否需要執行postProcessBeforeDestruction方法 * * @param bean 執行Destruction的bean * @return 是否需要執行postProcessBeforeDestruction方法 */ default boolean requiresDestruction(Object bean) { return true; } }
DestructionAwareBeanPostProceesor繼承自BeanPostProcessor介面,所以也可以重寫前值和後置處理。
下面介紹使用示例,建立MyDestructionAwareBeanPostProceesor,繼承DestructionAwareBeanPostProceesor介面:
@Slf4j public class MyDestructionAwareBeanPostProcessor implements DestructionAwareBeanPostProcessor { @Override public void postProcessBeforeDestruction(Object bean, String beanName) throws BeansException { log.info("DestructionAwareBeanPostProcessor.postProcessBeforeDestruction, \n\tbeanName:{}, bean:{}", beanName, bean); } @Override public boolean requiresDestruction(Object bean) { return true; // 返回true,一律執行postProcessBeforeDestruction方法 // 如果返回false,則不執行postProcessBeforeDestruction方法 } }
修改配置檔案:
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <bean class="cn.ganlixin.entity.Student" id="student"> <property name="id" value="99"/> <property name="name" value="張三"/> </bean> <bean class="cn.ganlixin.entity.User" id="user"> <property name="id" value="88"/> <property name="name" value="王五"/> </bean> <!-- 將實現了DestructionAwareBeanPostProcessor介面的實現類宣告為bean> --> <bean class="cn.ganlixin.processor.MyDestructionAwareBeanPostProcessor"/> </beans>
測試程式:
@Slf4j public class Test { public static void main(String[] args) { // 使用ApplicationContext來載入配置 ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml"); Student student = context.getBean("student", Student.class); User user = context.getBean("user", User.class); log.info("測試程式獲取到的student bean:{}", student); // 獲取bean工廠,然後呼叫destroyBean銷燬bean AutowireCapableBeanFactory factory = context.getAutowireCapableBeanFactory(); factory.destroyBean(student); } }
執行測試程式,輸出如下:
INFO [main] cn.ganlixin.Test - 測試程式獲取到的student bean:Student(id=99, name=張三) INFO [main] cn.ganlixin.processor.MyDestructionAwareBeanPostProcessor - DestructionAwareBeanPostProcessor.postProcessBeforeDestruction, beanName:cn.ganlixin.entity.Student, bean:Student(id=99, name=張三)
可以看到,在手動呼叫destroyBean方法來銷燬student bean的時候,呼叫了MyDestructionAwareBeanPostProcessor中定義的方法。
需要注意的是,雖然這裡使用destroyBean來銷燬了student bean,如果又通過getBean來獲取student bean,則會重新建立student bean。
七.DisposableBean介面
前面介紹了DestructionAwareBeanPostProcessor介面,可以對所有的bean設定銷燬(destruction)後的處理操作。
而這裡介紹的DisposableBean介面,就是對單獨的Bean進行destrction後的處理,也就是說不是應用到所有的bean上。
簡單介紹一下用法,建立Student類和User類,User類正常(不實現任何介面),Student類實現DisposableBean介面,然後重寫destroy方法:
@Data @Slf4j public class Student implements DisposableBean { private Integer id; private String name; @Override public void destroy() throws Exception { log.info("DisposableBean.destroy, this:{}", this); } } @Data public class User { private Integer id; private String name; }
建立配置檔案:
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <bean class="cn.ganlixin.entity.Student" id="student"> <property name="id" value="99"/> <property name="name" value="張三"/> </bean> <bean class="cn.ganlixin.entity.User" id="user"> <property name="id" value="88"/> <property name="name" value="王五"/> </bean> </beans>
測試程式:
@Slf4j public class Test { public static void main(String[] args) { // 使用ApplicationContext來載入配置 ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml"); Student student = context.getBean("student", Student.class); User user = context.getBean("user", User.class); log.info("測試程式獲取到的student bean:{}", student); log.info("測試程式獲取到的user bean:{}",user); // 獲取bean工廠,然後呼叫destroyBean銷燬bean AutowireCapableBeanFactory factory = context.getAutowireCapableBeanFactory(); factory.destroyBean(student); factory.destroyBean(user); } }
執行輸出:
INFO [main] cn.ganlixin.Test - 測試程式獲取到的student bean:Student(id=99, name=張三) INFO [main] cn.ganlixin.Test - 測試程式獲取到的user bean:User(id=88, name=王五) INFO [main] cn.ganlixin.entity.Student - DisposableBean.destroy, this:Student(id=99, name=張三)
可以看到,雖然測試程式碼中destroy了student和user兩個bean,但是隻有student bean在銷燬時觸發了DisposableBean的destory方法。
八.destroy-method方法
和init-method相對應的就是destory-method方法了,建立Student類,增加clean方法(自定義):
@Data @Slf4j public class Student { private Integer id; private String name; public void clean() { log.info("Student.clean, this:{}", this); } }
修改配置檔案,<bean>標籤中使用destroy-method屬性,值為clean方法
<bean class="cn.ganlixin.entity.Student" id="student" destroy-method="clean"> <property name="id" value="99"/> <property name="name" value="張三"/> </bean>
測試程式:
@Slf4j public class Test { public static void main(String[] args) { // 使用ApplicationContext來載入配置 ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml"); Student student = context.getBean("student", Student.class); log.info("測試程式獲取到的student bean:{}", student); // 刪除bean BeanDefinitionRegistry registry = (BeanDefinitionRegistry) context.getAutowireCapableBeanFactory(); registry.removeBeanDefinition("student"); } }
輸出:
INFO [main] cn.ganlixin.Test - 測試程式獲取到的student bean:Student(id=99, name=張三) INFO [main] cn.ganlixin.entity.Student - Student.clean, this:Student(id=99, name=張三)
九.宣告週期大雜燴
上面對每一種介面都做了介紹,這裡就將所有介面都做一下整合,嘗試在一個測試程式中測試所有介面,這個過程中就會對Bean的生命週期有清晰的認識:
9.1 實現多介面的Student類
建立Student類,實現Aware、InitializingBean、DisposableBean介面,並且增加display、clean方法,作為init-method和destory-method。
package cn.ganlixin.entity; import lombok.Data; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.BeansException; import org.springframework.beans.factory.*; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; @Data @Slf4j public class Student implements BeanNameAware, BeanFactoryAware, ApplicationContextAware, InitializingBean, DisposableBean { private Integer id; private String name; @Override public void setBeanName(String s) { log.info("BeanNameAware.setBeanName, this:{}", this); } @Override public void setBeanFactory(BeanFactory beanFactory) throws BeansException { log.info("BeanFactoryAware.setBeanFactory, this:{}", this); } @Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { log.info("ApplicationContextAware.setApplicationContext, this:{}", this); } @Override public void afterPropertiesSet() throws Exception { log.info("InitialingBean.afterPropertiesSet, this:{}", this); } @Override public void destroy() throws Exception { log.info("DisposableBean.destory, this:{}", this); } public void display() { log.info("init-method, Student.display, this:{}", this); } public void clean() { log.info("destroy-method, Student.clean, this:{}", this); } }
9.2 BeanPostProcessor前後置處理
建立MyBeanPostProcessor介面實現類,並重寫前置和後置處理方法:
package cn.ganlixin.processor; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.BeansException; import org.springframework.beans.factory.config.BeanPostProcessor; @Slf4j public class MyBeanPostProcessor implements BeanPostProcessor { @Override public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { log.info("MyBeanPostProcessor.postProcessBeforeInitialization, beanName:{}, bean:{}", beanName, bean); return bean; } @Override public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { log.info("MyBeanPostProcessor.postProcessAfterInitialization, beanName:{}, bean:{}", beanName, bean); return bean; } }
9.3 DestructionAwareBeanPostPrecessor介面
建立MyDestructionAwareBeanPostProcessor類,並重寫其中的方法(不重寫BeanPostProcessor的前後置處理方法):
package cn.ganlixin.processor; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.BeansException; import org.springframework.beans.factory.config.DestructionAwareBeanPostProcessor; @Slf4j public class MyDestructionAwareBeanPostProcessor implements DestructionAwareBeanPostProcessor { @Override public void postProcessBeforeDestruction(Object bean, String beanName) throws BeansException { log.info("DestructionAwareBeanPostProcessor.postProcessBeforeDestruction, \n\tbeanName:{}, bean:{}", beanName, bean); } @Override public boolean requiresDestruction(Object bean) { return true; // 返回true,一律執行postProcessBeforeDestruction方法 // 如果返回false,則不執行postProcessBeforeDestruction方法 } }
9.4 配置xml檔案
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.springframework.org/schema/beans" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <!-- 建立student bean,指定init-method和destroy-method --> <bean class="cn.ganlixin.entity.Student" id="student" init-method="display" destroy-method="clean"> <property name="id" value="99"/> <property name="name" value="張三"/> </bean> <!-- 將實現了DestructionAwareBeanPostProcessor介面的實現類宣告為bean--> <bean class="cn.ganlixin.processor.MyDestructionAwareBeanPostProcessor"/> <!-- 將實現了BeanPostProcessor介面的類也宣告為bean--> <bean class="cn.ganlixin.processor.MyBeanPostProcessor"/> </beans>
9.5 測試程式碼
package cn.ganlixin; import cn.ganlixin.entity.Student; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.support.BeanDefinitionRegistry; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; @Slf4j public class Test { public static void main(String[] args) { // 使用ApplicationContext來載入配置 ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml"); Student student = context.getBean("student", Student.class); log.info("測試程式獲取到的student bean:{}", student); // 刪除bean BeanDefinitionRegistry factory = (BeanDefinitionRegistry) context.getAutowireCapableBeanFactory(); factory.removeBeanDefinition("student"); } }
9.6 輸出結果
INFO [main] cn.ganlixin.entity.Student - BeanNameAware.setBeanName, this:Student(id=99, name=張三) INFO [main] cn.ganlixin.entity.Student - BeanFactoryAware.setBeanFactory, this:Student(id=99, name=張三) INFO [main] cn.ganlixin.entity.Student - ApplicationContextAware.setApplicationContext, this:Student(id=99, name=張三) INFO [main] cn.ganlixin.processor.MyBeanPostProcessor - MyBeanPostProcessor.postProcessBeforeInitialization, beanName:student, bean:Student(id=99, name=張三) INFO [main] cn.ganlixin.entity.Student - InitialingBean.afterPropertiesSet, this:Student(id=99, name=張三) INFO [main] cn.ganlixin.entity.Student - init-method, Student.display, this:Student(id=99, name=張三) INFO [main] cn.ganlixin.processor.MyBeanPostProcessor - MyBeanPostProcessor.postProcessAfterInitialization, beanName:student, bean:Student(id=99, name=張三) INFO [main] cn.ganlixin.Test - 測試程式獲取到的student bean:Student(id=99, name=張三) INFO [main] cn.ganlixin.processor.MyDestructionAwareBeanPostProcessor - DestructionAwareBeanPostProcessor.postProcessBeforeDestruction, beanName:student, bean:Student(id=99, name=張三) INFO [main] cn.ganlixin.entity.Student - DisposableBean.destory, this:Student(id=99, name=張三) INFO [main] cn.ganlixin.entity.Student - destroy-method, Student.clean, this:Student(id=99, name=張三)
十.總結
看了上面這個輸出結果,再結合下面這個圖,基本就能掌握Bean的大致生命週期了。
原文地址:https://www.cnblogs.com/-beyond/p/13188675.html