一文搞懂Spring Bean中的作用域和生命周期
一、Spring Bean 作用域
常規的 Spring IoC 容器中Bean的作用域有兩種:singleton
(單例)和prototype
(非單例)
註:基於Web的容器還有其他種作用域,在這就不贅述瞭。
singleton(單例)
singleton
是Spring默認的作用域。當 Bean 的作用域為 singleton 時,Spring IoC 容器中隻會存在一個共享的 Bean 實例。可以更好地重用對象,節省重復創建對象的開銷。- 設置方式:將 <bean> 元素的 scope 屬性設置為
singleton
(其實也可以不用設置,因為spring默認就是單例模式)
案例1
1.創建Dept類
public class Dept { //部門編號 private int deptNo; //部門名稱 private String deptName; }
2.編寫Spring配置文件,並將scope 屬性設置為singleton
<bean id="dept" class="com.bighorn.pojo.Dept" scope="singleton"> </bean>
3.編寫運行程序
public static void main(String[] args) { //獲取IoC容器 ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml"); //從容器中獲取對象 Dept dept1 = context.getBean("dept", Dept.class); Dept dept2 = context.getBean("dept", Dept.class); //打印對象 System.out.println(dept1); System.out.println(dept2); }
4.結果如下,可以發現打印出的是同一個對象
prototype(原型)
prototype
表示原型(非單例)模式。當 Bean 的作用域為 prototype時,Spring 容器會在每次請求該 Bean 時,都創建一個新的 Bean 實例。- 設置方式:將 <bean> 元素的 scope 屬性設置為
prototype
案例2
1.隻需修改scope 屬性為prototype
,其他代碼不變。
<bean id="dept" class="com.bighorn.pojo.Dept" scope="prototype"> </bean>
2.運行結果如下
小結
spring bean默認為單例,避免瞭對象的頻繁創建與銷毀,達到瞭bean對象的復用,性能高。
像表現層、業務層、數據層、工具類對象隻需要調用方法,比較適合交給Spring IoC容器管理
但是像那種需要封裝實例的域對象,因為會引發線程安全問題,不適合交給Spring IoC容器管理。
二、Spring Bean生命周期
Spring Bean生命周期:Spring Bean 對象從創建到銷毀的整體過程。
Spring Bean生命周期大致可以分為以下 5 個階段:1.Bean 的實例化、2.Bean 屬性賦值、3.Bean 的初始化、4.Bean 的使用、5.Bean 的銷毀
Spring 根據 Bean 的作用域來選擇 Bean 的管理方式。
- 對於 singleton 作用域的 Bean ,Spring IoC 容器能夠一直追蹤bean的生命周期;
- 對於 prototype 作用域的 Bean ,Spring IoC 容器隻負責創建,然後就將 Bean 的實例交給客戶端代碼管理,Spring IoC 容器將不再跟蹤其生命周期。
綜上所述: 為瞭更好研究如何控制bean周期,下面案例中創建的bean默認都使用單例模式。
如何關閉容器
由於ApplicationContext
類中沒有關閉容器的方法,所以想要關閉容器需要用到ApplicationContext
的子類——ClassPathXmlApplicationContext
類。該類又有兩種方法可以關閉容器
1、close關閉容器
close()
方法,在調用的時候關閉容器
//獲取 ClassPathXmlApplicationContext 容器 ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml"); //調用close方法關閉容器 context.close();
2、註冊鉤子關閉容器
registerShutdownHook()
方法,在JVM退出前調用關閉容器
//獲取 ClassPathXmlApplicationContext 容器 ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml"); //調用註冊狗子關閉容器 context.registerShutdownHook();
生命周期回調
Bean 的生命周期回調方法主要有兩種:
- 初始化回調方法:在 Spring Bean 被初始化後調用,執行一些自定義的回調操作。
- 銷毀回調方法:在 Spring Bean 被銷毀前調用,執行一些自定義的回調操作。
我們可以通過以下 2種方式自定義 Bean 的生命周期回調方法:
- 通過接口實現
- 通過 XML 配置實現
通過接口設置生命周期
我們可以在 Spring Bean 的 Java 類中,通過實現 InitializingBean
和 DisposableBean
接口,指定 Bean 的生命周期回調方法。
案例1
1.創建User類,並實現InitializingBean
, DisposableBean
接口,重寫afterPropertiesSet()
和destroy()
方法。代碼如下
/** * 繼承接口,程序初始化回調和銷毀回調方法 */ public class User implements InitializingBean, DisposableBean { String name; int age; //setter方法 public void setName(String name) { this.name = name; } public void setAge(int age) { this.age = age; } //初始化回調方法 @Override public void afterPropertiesSet() throws Exception { System.out.println("這是初始化回調方法"); } //銷毀回調方法 @Override public void destroy() throws Exception { System.out.println("這是銷毀回調方法"); } //toString方法 @Override public String toString() { return "User{" + "name='" + name + '\'' + ", age=" + age + '}'; } }
2.編寫spring配置文件
<bean id="user" class="com.bighorn.pojo.User"> <property name="name" value="bighorn"/> <property name="age" value="18"/> </bean>
3.編寫運行程序
public class App { public static void main(String[] args) { //獲取 ClassPathXmlApplicationContext 容器 ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml"); //從容器中獲取對象 User user = context.getBean("user", User.class); //使用bean System.out.println(user); //調用close方法關閉容器 context.close(); } }
4.運行結果如下
通過xml設置生命周期
註意:由於通過接口設置生命周期的方式會導致代碼的耦合性過高,所以通常情況下,我們會通過xml設置生命周期。
通過 <bean> 元素中的 init-method
和 destory-method
屬性,指定 Bean 的生命周期回調方法。
案例2
1.創建User類,這次不需要繼承那兩個接口瞭,但要在添加兩個普通方法(方法名可任意):init()
和destory()
代表初始化和銷毀方法。代碼如下
/** * 通過XML配置指定回調方法 */ public class User { String name; int age; //setter方法 public void setName(String name) { this.name = name; } public void setAge(int age) { this.age = age; } //初始化回調方法 public void init() throws Exception { System.out.println("這是初始化回調方法"); } //銷毀回調方法 public void destroy() throws Exception { System.out.println("這是銷毀回調方法"); } //toString方法 @Override public String toString() { return "User{" + "name='" + name + '\'' + ", age=" + age + '}'; } }
2.編寫spring配置文件,在<bean>元素裡添加init-method
和destroy-method
屬性,並指定User類中自定義的init和destory方法(關鍵)
<!--通過XML配置指定回調方法--> <bean id="user" class="com.bighorn.pojo.User" init-method="init" destroy-method="destroy"> <property name="name" value="bighorn"/> <property name="age" value="18"/> </bean>
3.運行程序和運行結果都與案例1相同,這裡就少些筆墨介紹瞭
到此這篇關於一文搞懂Spring Bean中的作用域和生命周期的文章就介紹到這瞭,更多相關Spring Bean作用域 生命周期內容請搜索WalkonNet以前的文章或繼續瀏覽下面的相關文章希望大傢以後多多支持WalkonNet!
推薦閱讀:
- 詳解Spring Bean的配置方式與實例化
- 詳解Spring中Bean後置處理器(BeanPostProcessor)的使用
- Spring Bean屬性註入的兩種方式詳解
- 詳解Spring Bean的集合註入和自動裝配
- 詳解SpringIOC容器中bean的作用范圍和生命周期