Java開發(fā)學習之Bean的生命周期詳解
一、什么是生命周期
首先理解下什么是生命周期?
從創(chuàng)建到消亡的完整過程,例如人從出生到死亡的整個過程就是一個生命周期。
bean生命周期是什么?
bean對象從創(chuàng)建到銷毀的整體過程。
bean生命周期控制是什么?
在bean創(chuàng)建后到銷毀前做一些事情。
二、環(huán)境準備
環(huán)境搭建:
- 創(chuàng)建一個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(); ? } }
三、生命周期設置
接下來,在上面這個環(huán)境中來為BookDao添加生命周期的控制方法,具體的控制有兩個階段:
- bean創(chuàng)建之后,想要添加內(nèi)容,比如用來初始化需要用到資源
- bean銷毀之前,想要添加內(nèi)容,比如用來釋放用到的資源
步驟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方法執(zhí)行了,但是destroy方法卻未執(zhí)行,這是為什么呢?
- Spring的IOC容器是運行在JVM中
- 運行main方法后,JVM啟動,Spring加載配置文件生成IOC容器,從容器獲取bean對象,然后調(diào)方法執(zhí)行
- main方法執(zhí)行完后,JVM退出,這個時候IOC容器中的bean還沒有來得及銷毀就已經(jīng)結束了
- 所以沒有調(diào)用對應的destroy方法
知道了出現(xiàn)問題的原因,具體該如何解決呢?
四、close關閉容器
ApplicationContext中沒有close方法
需要將ApplicationContext更換成ClassPathXmlApplicationContext
ClassPathXmlApplicationContext ctx = new ? ?ClassPathXmlApplicationContext("applicationContext.xml");
調(diào)用ctx的close()方法
ctx.close();
運行程序,就能執(zhí)行destroy方法的內(nèi)容
這種方式比較暴力,直接就關閉掉容器了,接下來介紹另一種方式,
五、注冊鉤子關閉容器
在容器未關閉之前,提前設置好回調(diào)函數(shù),讓JVM在退出之前回調(diào)此函數(shù)來關閉容器
調(diào)用ctx的registerShutdownHook()方法
是全局變量,方法放置位置無所謂
ctx.registerShutdownHook();
注意:registerShutdownHook在ApplicationContext中也沒有
運行后,查詢打印結果
兩種方式介紹完后,close和registerShutdownHook選哪個?
相同點:這兩種都能用來關閉容器
不同點:close()是在調(diào)用的時候關閉,registerShutdownHook()是在JVM退出前調(diào)用關閉。
分析上面的實現(xiàn)過程,會發(fā)現(xiàn)添加初始化和銷毀方法,即需要編碼也需要配置,實現(xiàn)起來步驟比較多也比較亂。
Spring提供了兩個接口來完成生命周期的控制,好處是可以不用再進行配置init-method
和destroy-method
接下來在BookServiceImpl完成這兩個接口的使用:
修改BookServiceImpl類,添加兩個接口InitializingBean
, DisposableBean
并實現(xiàn)接口中的兩個方法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類
那第二種方式的實現(xiàn),我們也介紹完了。
小細節(jié)
對于InitializingBean接口中的afterPropertiesSet方法,翻譯過來為屬性設置之后。
對于BookServiceImpl來說,bookDao是它的一個屬性
setBookDao方法是Spring的IOC容器為其注入屬性的方法
思考:afterPropertiesSet和setBookDao誰先執(zhí)行?
從方法名分析,猜想應該是setBookDao方法先執(zhí)行
驗證思路,在setBookDao方法中添加一句話
public void setBookDao(BookDao bookDao) { ? ? ? ?System.out.println("set ....."); ? ? ? ?this.bookDao = bookDao; ? } ?
重新運行AppForLifeCycle,打印結果如下:
驗證的結果和我們猜想的結果是一致的,所以初始化方法會在類中屬性設置之后執(zhí)行。
六、bean生命周期總結
(1)關于Spring中對bean生命周期控制提供了兩種方式:
- 在配置文件中的bean標簽中添加
init-method
和destroy-method
屬性 - 類實現(xiàn)
InitializingBean
與DisposableBean
接口。
(2)對于bean的生命周期控制在bean的整個生命周期中所處的位置如下:
初始化容器
- 1.創(chuàng)建對象(內(nèi)存分配)
- 2.執(zhí)行構造方法
- 3.執(zhí)行屬性注入(set操作)
- 4.執(zhí)行bean初始化方法
使用bean
- 1.執(zhí)行業(yè)務操作
關閉/銷毀容器
- 1.執(zhí)行bean銷毀方法
(3)關閉容器的兩種方式:
ConfigurableApplicationContext是ApplicationContext的子類
- close()方法
- registerShutdownHook()方法
到此這篇關于Java開發(fā)學習之Bean的生命周期詳解的文章就介紹到這了,更多相關Bean生命周期內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
java實現(xiàn)基于SGIP協(xié)議開發(fā)聯(lián)通短信的方法
這篇文章主要介紹了java實現(xiàn)基于SGIP協(xié)議開發(fā)聯(lián)通短信的方法,涉及java短信發(fā)送的相關實現(xiàn)技巧,具有一定參考借鑒價值,需要的朋友可以參考下2015-07-07解決mybatis where-if中if不能識別大寫AND,OR的問題
這篇文章主要介紹了解決mybatis where-if中if不能識別大寫AND,OR的問題,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2021-02-02