Spring注解驅(qū)動(dòng)之關(guān)于@Bean注解指定初始化和銷毀的方法
bean的生命周期
通常意義上講的bean的生命周期,指的是bean從創(chuàng)建到初始化,經(jīng)過一系列的流程,最終銷毀的過程。
只不過,在Spring中,bean的生命周期是由Spring容器來管理的。
在Spring中,我們可以自己來指定bean的初始化和銷毀的方法。
我們指定了bean的初始化和銷毀方法之后,當(dāng)容器在bean進(jìn)行到當(dāng)前生命周期的階段時(shí),會(huì)自動(dòng)調(diào)用我們自定義的初始化和銷毀方法。
如何定義初始化、銷毀方法
可以通過@Bean注解指定初始化、銷毀方法。
如果使用XML配置文件的方式配置bean的話,那么可以在標(biāo)簽中指定bean的初始化和銷毀方法,如下所示:
<bean id="person" class="com.meimeixia.bean.Person" init-method="init" destroy-method="destroy"> <property name="age" value="18"></property> <property name="name" value="liayun"></property> </bean>
這里需要注意的是,我們自己寫的Person類中,需要存在init()方法和destroy()方法。而且Spring中還規(guī)定,這里的init()方法和destroy()方法必須是無參的,但可以拋出異常。
如果我們使用注解的方式,那么該如何實(shí)現(xiàn)指定bean的初始化和銷毀方法呢?
首先創(chuàng)建一個(gè)名稱為Car的類,這個(gè)類的實(shí)現(xiàn)比較簡(jiǎn)單,如下所示:
package com.meimeixia.bean; public class Car { public Car() { System.out.println("car constructor..."); } public void init() { System.out.println("car ... init..."); } public void destroy() { System.out.println("car ... destroy..."); } }
然后將Car類對(duì)象通過注解的方式注冊(cè)到Spring容器中。
package com.meimeixia.config; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import com.meimeixia.bean.Car; @Configuration public class MainConfigOfLifeCycle { @Bean public Car car() { return new Car(); } }
接著來寫一個(gè)測(cè)試類
package com.meimeixia.test; import org.junit.Test; import org.springframework.context.annotation.AnnotationConfigApplicationContext; import com.meimeixia.config.MainConfigOfLifeCycle; public class IOCTest_LifeCycle { @Test public void test01() { // 1. 創(chuàng)建IOC容器 AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfigOfLifeCycle.class); System.out.println("容器創(chuàng)建完成"); } }
對(duì)于單實(shí)例bean對(duì)象來說,在Spring容器創(chuàng)建完成后,就會(huì)對(duì)單實(shí)例bean進(jìn)行實(shí)例化。
可以看到,在Spring容器創(chuàng)建完成時(shí),會(huì)自動(dòng)調(diào)用單實(shí)例bean的構(gòu)造方法,對(duì)單實(shí)例bean進(jìn)行了實(shí)例化操作。
總之,對(duì)應(yīng)單實(shí)例bean來說,會(huì)在Spring容器啟動(dòng)的時(shí)候創(chuàng)建對(duì)象;對(duì)于多實(shí)例bean來說,會(huì)在多次獲取bean的時(shí)候創(chuàng)建對(duì)象。
@Bean注解的initMethod和destroyMethod樹形來指定bean的初始化方法和銷毀方法。
所以我們?cè)谂渲妙惖腀Bean注解中指定initMethod屬性和destroyMethod屬性。
package com.meimeixia.config; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import com.meimeixia.bean.Car; @Configuration public class MainConfigOfLifeCycle { @Bean(initMethod="init", destroyMethod="destroy") public Car car() { return new Car(); } }
再次執(zhí)行測(cè)試方法。
在輸出結(jié)果中可以看出,在Spring容器中,先是調(diào)用了Car類的構(gòu)造方法來創(chuàng)建Car對(duì)象,接下來便是調(diào)用了Car對(duì)象的init方法來進(jìn)行初始化。
這里有個(gè)問題,在運(yùn)行測(cè)試方法的時(shí)候沒有打印出bean的銷毀方法中的信息,那么什么時(shí)候執(zhí)行bean的銷毀方法呢?bean的銷毀方法時(shí)在容器關(guān)閉的時(shí)候被調(diào)用的。
所以,在測(cè)試方法中添加關(guān)閉容器的代碼(注意關(guān)閉的容器的方法ApplicationContext沒有)。
package com.meimeixia.test; import org.junit.Test; import org.springframework.context.annotation.AnnotationConfigApplicationContext; import com.meimeixia.config.MainConfigOfLifeCycle; public class IOCTest_LifeCycle { @Test public void test01() { // 1. 創(chuàng)建IOC容器 AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfigOfLifeCycle.class); System.out.println("容器創(chuàng)建完成"); // 關(guān)閉容器 applicationContext.close(); } }
再次運(yùn)行測(cè)試方法。
可以看出,此時(shí)輸出了對(duì)象的銷毀方法中的信息,說明執(zhí)行了對(duì)象的銷毀方法。
初始化、銷毀方法的使用場(chǎng)景
一個(gè)典型的場(chǎng)景就是對(duì)于數(shù)據(jù)源的管理。例如,在配置數(shù)據(jù)源時(shí),在初始化的時(shí)候,會(huì)對(duì)很多的數(shù)據(jù)源的屬性進(jìn)行賦值操作;在銷毀的時(shí)候,我們需要對(duì)數(shù)據(jù)源的連接等信息進(jìn)行關(guān)閉和清理。這個(gè)時(shí)候,我們就可以在自定義的初始化和銷毀方法中自定義操作邏輯。
初始化、銷毀方法在Spring中的調(diào)用時(shí)機(jī)
你有沒有想過這樣一個(gè)問題,初始化方法和銷毀方法是在什么時(shí)候被調(diào)用的呢?
bean對(duì)象的初始化方法調(diào)用的時(shí)機(jī)
對(duì)象創(chuàng)建完成,如果對(duì)象中存在一些屬性,并且這些屬性也都已經(jīng)賦值了,那么就會(huì)調(diào)用bean的初始化方法。對(duì)于單實(shí)例bean來說,在Spring容器創(chuàng)建完成后,Spring容器會(huì)自動(dòng)調(diào)用bean的初始化方法;對(duì)應(yīng)多實(shí)例bean來說,在每次獲取bean對(duì)象的時(shí)候,調(diào)用bean的初始化方法。
bean對(duì)象的銷毀方法調(diào)用的時(shí)機(jī):對(duì)于單實(shí)例bean來說,在容器關(guān)閉的時(shí)候,會(huì)調(diào)用bean的銷毀方法;對(duì)于多實(shí)例bean來說,Spring容器只負(fù)責(zé)創(chuàng)建bean不會(huì)管理這些bean,也就不會(huì)自動(dòng)調(diào)用這個(gè)bean的銷毀方法了。小伙伴只能手動(dòng)調(diào)用多實(shí)例bean的銷毀方法了。
多實(shí)例bean初始化、銷毀
在配置類上通過@Scope注解將Car對(duì)象設(shè)置成多實(shí)例bean。
package com.meimeixia.config; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Scope; import com.meimeixia.bean.Car; @Configuration public class MainConfigOfLifeCycle { @Scope("prototype") @Bean(initMethod="init", destroyMethod="destroy") public Car car() { return new Car(); } }
修改一下測(cè)試方法。
@Test public void test01() { // 1. 創(chuàng)建IOC容器 AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfigOfLifeCycle.class); System.out.println("容器創(chuàng)建完成"); }
運(yùn)行測(cè)試方法。
可以看到,將Car對(duì)象設(shè)置成多實(shí)例bean,并且沒有獲取bean實(shí)例對(duì)象時(shí),Spring容器并沒有執(zhí)行bean的構(gòu)造方法、初始化方法和銷毀方法。
如果我們?cè)跍y(cè)試方法獲取一下Car實(shí)例結(jié)果是什么樣呢?
可以看到,結(jié)果信息中輸出了構(gòu)造方法和初始化方法中的信息。
當(dāng)我們?cè)讷@取多實(shí)例bean對(duì)象的時(shí)候,會(huì)創(chuàng)建對(duì)象并進(jìn)行初始化,但是銷毀方法時(shí)在什么時(shí)候被調(diào)用呢?是在容器關(guān)閉的時(shí)候么?我們現(xiàn)在來驗(yàn)證一下。
@Test public void test01() { // 1. 創(chuàng)建IOC容器 AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfigOfLifeCycle.class); System.out.println("容器創(chuàng)建完成"); applicationContext.getBean("car"); // 多實(shí)例bean在獲取的時(shí)候才創(chuàng)建對(duì)象 // 關(guān)閉容器 applicationContext.close(); }
可以看到,多實(shí)例的bean在容器關(guān)閉的時(shí)候是不會(huì)進(jìn)行銷毀的,也就是說你每次獲取時(shí),IOC容器幫你創(chuàng)建出對(duì)象交還給你,至于要什么時(shí)候銷毀是你自己的事,Spring容器只負(fù)責(zé)創(chuàng)建多實(shí)例不再負(fù)責(zé)管理多實(shí)例bean了。
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
- Springboot @Configuration @bean注解作用解析
- Spring @Bean注解配置及使用方法解析
- SpringBoot配置@Configuration注解和@bean注解
- SpringBoot?@Configuration與@Bean注解使用介紹
- Spring?@Bean注解深入分析源碼執(zhí)行過程
- 關(guān)于spring的@Bean注解放入引用Bean中初始化失敗分析
- Spring @Bean注解的使用場(chǎng)景與案例實(shí)現(xiàn)
- spring中@Configuration和@Bean注解的用法
- 深入解析Spring中的@Bean注解
- 一文讀懂Spring中@Bean注解的核心作用
相關(guān)文章
Java調(diào)用高德地圖API根據(jù)詳細(xì)地址獲取經(jīng)緯度詳細(xì)教程
寫了一個(gè)經(jīng)緯度相關(guān)的工具,分享給有需求的小伙伴們,下面這篇文章主要給大家介紹了關(guān)于Java調(diào)用高德地圖API根據(jù)詳細(xì)地址獲取經(jīng)緯度,文中通過圖文以及代碼介紹的非常詳細(xì),需要的朋友可以參考下2024-04-04詳解springboot + profile(不同環(huán)境讀取不同配置)
本篇文章主要介紹了springboot + profile(不同環(huán)境讀取不同配置),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-05-05Spring+Junit4進(jìn)行接口測(cè)試實(shí)例代碼
這篇文章主要介紹了Spring+Junit4進(jìn)行接口測(cè)試實(shí)例代碼,涉及pom.xml、bean的配置,以及接口測(cè)試代碼等相關(guān)內(nèi)容,小編覺得還是挺不錯(cuò)的,這里分享給大家,需要的朋友可以參考下2018-01-01手把手教你實(shí)現(xiàn)idea中配置國內(nèi)源
idea的國內(nèi)源配置十分重要,能夠提升程序開發(fā)的效率而且也是減少bug的一種有效防范,本文就來介紹一下idea中配置國內(nèi)源,具有一定的參考價(jià)值,感興趣的可以了解一下2023-07-07