Spring容器可以管理singleton作用域的Bean的生命週期,可以呼叫建立、初始化、銷燬等生命週期的方法。
對於prototype作用域的Bean,Spring容器只負責建立,建立後Bean的例項就交給客戶端程式碼來管理,Spring容器不再跟蹤其生命週期。
Bean的生命週期
1、根據配置情況,呼叫Bean的構造方法或工廠方法例項化Bean
2、利用依賴注入完成Bean中所有屬性值的配置注入
3、如果Bean實現了BeanNameAware介面,則呼叫setBeanName()方法傳入當前Bean的id。
4、如果Bean實現了BeanFactoryAware介面,則呼叫setBeanFactory()傳入當前工廠例項的引用
5、如果Bean實現了ApplicationContextAware介面,則呼叫setApplicationContext()方法傳入當前ApplicationContext例項的引用
6、如果BeanPostProcessor和Bean關聯,則呼叫預初始化方法postProcessBeforeInitialzation()進行加工操作,Spring AOP即利用此實現。
7、如果Bean實現了InitializingBean介面,則呼叫afterPropertiesSet()方法
8、如果在配置檔案中通過init-method屬性指定了初始化方法,則呼叫初始化方法
9、如果BeanPostProcessor和Bean關聯,則呼叫初始化方法postProcessAfterInitialization()。此時,Bean已經可以被正常使用了。
10、如果指定了作用域為singleton,則將例項放在Spring IoC的快取池中,並觸發Spring容器對該Bean的生命週期管理,如果指定作用域為prototype,則將該Bean交給呼叫者,由呼叫者管理該Bean的生命週期。
11、如果Bean實現了DisposableBean介面,則呼叫destory()方法銷燬例項;
12、如果在配置檔案中通過destory-method指定了Bean的銷燬方法,則呼叫該方法銷燬例項。
說明:
以上介面中,均只有一個方法。
並不建議讓Bean實現多個介面,因為繼承多個介面會使程式碼耦合較高。
注入依賴後的行為
Spring提供2種方式,在Bean全部屬性設定完成後執行特定的行為:
- 實現InitializingBean介面,在afterPropertiesSet()方法中寫程式碼。InitializingBean介面中只有這一個方法。
- 在xml中使用init-method屬性指定要呼叫的方法
可以同時使用這2種方式,會先執行afterPropertiesSet(),再執行init-method屬性指定的方法。
Bean銷燬之前的行為
Spring提供了2種方式,在Bean銷燬之前執行特定的行為:
- 實現DisposableBean介面,該介面只有destory()方法
- 在xml中用destory-method屬性指定要呼叫的方法
可以同時使用這2種方式,會先執行destory(),再執行destory-method屬性指定的方法。
說明:同時使用時,都是先執行介面中的方法,再執行xml中指定的方法。
示例
1 class Student { 2 private String name; 3 4 public Student(String name){ 5 this.name=name; 6 } 7 8 public String getName(){ 9 return name; 10 } 11 } 12 13 class Teacher implements InitializingBean, DisposableBean { 14 @Autowired 15 private Student student; 16 17 public void say(){ 18 System.out.println(student.getName()+",叫家長來一下"); 19 } 20 21 public void xmlInit(){ 22 System.out.println("正在執行xml中init-method屬性指定的初始化方法"); 23 } 24 25 @Override 26 public void afterPropertiesSet() throws Exception { 27 System.out.println("正在執行InitializingBean介面中的afterPropertiesSet()方法"); 28 } 29 30 public void xmlDestory(){ 31 System.out.println("正在執行xml中destory-method屬性指定的方法"); 32 } 33 34 @Override 35 public void destroy() throws Exception { 36 System.out.println("正在執行DisposableBean介面中的destory()方法"); 37 } 38 } 39 40 public class Test { 41 public static void main(String[] args) { 42 AbstractApplicationContext applicationContext=new ClassPathXmlApplicationContext("applicationContext.xml"); 43 Teacher teacher=applicationContext.getBean("teacher",Teacher.class); 44 teacher.say(); 45 applicationContext.registerShutdownHook(); 46 } 47 48 }
在基於Web的Spring容器中,系統已經提供了相應的程式碼,在Web應用關閉時,會自動關閉Spring容器。
在非Web的Spring的容器中,需要手動呼叫AbstractApplicationContext類的registerShutdownHook()方法向JVM註冊一個關閉鉤子,執行完前面的程式碼,會自動關閉Spring容器。
ApplicatioContext即Spring容器。
ApplicationContext是介面,沒有實現registerShutdownHook()方法,AbstractApplicationContext是ApplicationContext的子類,實現了該方法,此處要宣告為AbstractApplicationContext,不能宣告為ApplicationContext。
xml中的配置:
<context:annotation-config /> <bean id="student" class="my_package.Student"> <constructor-arg value="張三" /> </bean> <bean id="teacher" class="my_package.Teacher" init-method="xmlInit" destroy-method="xmlDestory" />
執行程式,控制檯輸出如下:
正在執行InitializingBean介面中的afterPropertiesSet()方法 正在執行xml中init-method屬性指定的初始化方法 張三,叫家長來一下 正在執行DisposableBean介面中的destory()方法 正在執行xml中destory-method屬性指定的方法