一、什麼是生命週期
-
首先理解下什麼是生命週期?
-
從建立到消亡的完整過程,例如人從出生到死亡的整個過程就是一個生命週期。
-
-
-
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銷燬之前,想要新增內容,比如用來釋放用到的資源
步驟1:新增初始化和銷燬方法
針對這兩個階段,我們在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...");
}
}
步驟2:配置生命週期
在配置檔案新增配置,如下:
<bean id="bookDao" class="com.itheima.dao.impl.BookDaoImpl" init-method="init" destroy-method="destory"/>
步驟3:執行程式
執行AppForLifeCycle列印結果為:
從結果中可以看出,init方法執行了,但是destroy方法卻未執行,這是為什麼呢?
-
Spring的IOC容器是執行在JVM中
-
執行main方法後,JVM啟動,Spring載入配置檔案生成IOC容器,從容器獲取bean物件,然後調方法執行
-
main方法執行完後,JVM退出,這個時候IOC容器中的bean還沒有來得及銷燬就已經結束了
-
所以沒有呼叫對應的destroy方法
知道了出現問題的原因,具體該如何解決呢?
四、close關閉容器
-
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,列印結果如下:
驗證的結果和我們猜想的結果是一致的,所以初始化方法會在類中屬性設定之後執行。
-
六、bean生命週期總結
(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()方法
-