首頁 > 軟體

一文搞懂Spring Bean中的作用域和生命週期

2022-06-11 14:02:56

一、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 類中,通過實現 InitializingBeanDisposableBean 介面,指定 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-methoddestory-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-methoddestroy-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作用域 生命週期內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!


IT145.com E-mail:sddin#qq.com