首先理解下什麼是生命週期?
從建立到消亡的完整過程,例如人從出生到死亡的整個過程就是一個生命週期。
bean物件從建立到銷燬的整體過程。
bean生命週期控制是什麼?
在bean建立後到銷燬前做一些事情。
環境搭建:
建立一個Maven專案
pom.xml新增依賴
resources下新增spring的組態檔applicationContext.xml
最終專案的結構如下:
(1)專案中新增BookDao、BookDaoImpl、BookService和BookServiceImpl類
public interface BookDao {
public void save();
}
public class BookDaoImpl implements BookDao {
public void save() {
System.out.println("book dao save ...");
}
}
public interface BookService {
public void save();
}
public class BookServiceImpl implements BookService{
private BookDao bookDao;
public void setBookDao(BookDao bookDao) {
this.bookDao = bookDao;
}
public void save() {
System.out.println("book service save ...");
bookDao.save();
}
}
(2)resources下提供spring的組態檔
<?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 id="bookDao" class="com.itheima.dao.impl.BookDaoImpl"/>
</beans>
(3)編寫AppForLifeCycle執行類,載入Spring的IOC容器,並從中獲取對應的bean物件
public class AppForLifeCycle {
public static void main( String[] args ) {
ApplicationContext ctx = new
ClassPathXmlApplicationContext("applicationContext.xml");
BookDao bookDao = (BookDao) ctx.getBean("bookDao");
bookDao.save();
}
}
接下來,在上面這個環境中來為BookDao新增生命週期的控制方法,具體的控制有兩個階段:
bean建立之後,想要新增內容,比如用來初始化需要用到資源
bean銷燬之前,想要新增內容,比如用來釋放用到的資源
針對這兩個階段,我們在BooDaoImpl類中分別新增兩個方法,方法名任意
public class BookDaoImpl implements BookDao {
public void save() {
System.out.println("book dao save ...");
}
//表示bean初始化對應的操作
public void init(){
System.out.println("init...");
}
//表示bean銷燬前對應的操作
public void destory(){
System.out.println("destory...");
}
}
在組態檔新增設定,如下:
<bean id="bookDao" class="com.itheima.dao.impl.BookDaoImpl" init-method="init" destroy-method="destory"/>
執行AppForLifeCycle列印結果為:
從結果中可以看出,init方法執行了,但是destroy方法卻未執行,這是為什麼呢?
Spring的IOC容器是執行在JVM中
執行main方法後,JVM啟動,Spring載入組態檔生成IOC容器,從容器獲取bean物件,然後調方法執行
main方法執行完後,JVM退出,這個時候IOC容器中的bean還沒有來得及銷燬就已經結束了
所以沒有呼叫對應的destroy方法
知道了出現問題的原因,具體該如何解決呢?
ApplicationContext中沒有close方法
需要將ApplicationContext更換成ClassPathXmlApplicationContext
ClassPathXmlApplicationContext ctx = new
ClassPathXmlApplicationContext("applicationContext.xml");
呼叫ctx的close()方法
ctx.close();
執行程式,就能執行destroy方法的內容
這種方式比較暴力,直接就關閉掉容器了,接下來介紹另一種方式,
在容器未關閉之前,提前設定好回撥函數,讓JVM在退出之前回撥此函數來關閉容器
呼叫ctx的registerShutdownHook()方法
是全域性變數,方法放置位置無所謂
ctx.registerShutdownHook();
注意:registerShutdownHook在ApplicationContext中也沒有
執行後,查詢列印結果
兩種方式介紹完後,close和registerShutdownHook選哪個?
相同點:這兩種都能用來關閉容器
不同點:close()是在呼叫的時候關閉,registerShutdownHook()是在JVM退出前呼叫關閉。
分析上面的實現過程,會發現新增初始化和銷燬方法,即需要編碼也需要設定,實現起來步驟比較多也比較亂。
Spring提供了兩個介面來完成生命週期的控制,好處是可以不用再進行設定init-method
和destroy-method
接下來在BookServiceImpl完成這兩個介面的使用:
修改BookServiceImpl類,新增兩個介面InitializingBean
, DisposableBean
並實現介面中的兩個方法afterPropertiesSet
和destroy
public class BookServiceImpl implements BookService, InitializingBean, DisposableBean {
private BookDao bookDao;
public void setBookDao(BookDao bookDao) {
this.bookDao = bookDao;
}
public void save() {
System.out.println("book service save ...");
bookDao.save();
}
public void destroy() throws Exception {
System.out.println("service destroy");
}
public void afterPropertiesSet() throws Exception {
System.out.println("service init");
}
}
重新執行AppForLifeCycle類
那第二種方式的實現,我們也介紹完了。
小細節
對於InitializingBean介面中的afterPropertiesSet方法,翻譯過來為屬性設定之後
。
對於BookServiceImpl來說,bookDao是它的一個屬性
setBookDao方法是Spring的IOC容器為其注入屬性的方法
思考:afterPropertiesSet和setBookDao誰先執行?
從方法名分析,猜想應該是setBookDao方法先執行
驗證思路,在setBookDao方法中新增一句話
public void setBookDao(BookDao bookDao) {
System.out.println("set .....");
this.bookDao = bookDao;
}
重新執行AppForLifeCycle,列印結果如下:
驗證的結果和我們猜想的結果是一致的,所以初始化方法會在類中屬性設定之後執行。
(1)關於Spring中對bean生命週期控制提供了兩種方式:
在組態檔中的bean標籤中新增init-method
和destroy-method
屬性
類實現InitializingBean
與DisposableBean
介面。
(2)對於bean的生命週期控制在bean的整個生命週期中所處的位置如下:
初始化容器
1.建立物件(記憶體分配)
2.執行構造方法
3.執行屬性注入(set操作)
4.執行bean初始化方法
使用bean
1.執行業務操作
關閉/銷燬容器
1.執行bean銷燬方法
(3)關閉容器的兩種方式:
ConfigurableApplicationContext是ApplicationContext的子類
close()方法
registerShutdownHook()方法
本文來自部落格園,作者:|舊市拾荒|,轉載請註明原文連結:https://www.cnblogs.com/xiaoyh/p/16311026.html