1. 程式人生 > 實用技巧 >Spring詳解(十一)----Bean 的作用域

Spring詳解(十一)----Bean 的作用域

1、Bean 的作用域介紹

預設情況下,Spring 只為每個在 IOC 容器裡宣告的 Bean 建立唯一 一個例項,並且整個 IOC 容器範圍內都能共享該例項,所有後續的物件通過getBean() 呼叫和 Bean 的引用都將返回這個唯一的 Bean 例項。但是如果我們需要不同例項的Bean呢?這時就要提到Bean的作用域了,在Spring中預設的作用域為 Singleton,它是所有 Bean 的預設作用域。而在Spring 中提供了 5 種作用域,它會根據情況來決定是否生成新的物件,如下:

  1. singleton:單例模式,使用 singleton 定義的 Bean 在 Spring 容器中只有一個例項,這也是 Bean 預設的作用域。
  2. prototype:原型模式(多例模式),每次通過 Spring 容器獲取 prototype 定義的 Bean 時,容器都將建立一個新的 Bean 例項,即每次呼叫getBean()時。
  3. request:請求模式,請求用於Web開發,在一次 HTTP 請求中,容器會返回該 Bean 的同一個例項。而對不同的 HTTP 請求,會返回不同的例項,該作用域僅在當前 HTTP Request 內有效。
  4. session:會話模式,用於Web開發,在一次 HTTP Session 中,容器會返回該 Bean 的同一個例項。而對不同的 HTTP 請求,會返回不同的例項,該作用域僅在當前 HTTP Session 內有效。
  5. global Session(Spring5已經去除了):全域性會話模式,在一個全域性的 HTTP Session 中,容器會返回該 Bean 的同一個例項。該作用域僅在使用 portlet context 時有效。一般用於 Porlet 應用環境 , 分散式系統存在全域性 session 概念(單點登入),如果不是 porlet 環境,globalSession 等同於 Session

=====================================

我們可以通過XML<bean> 元素中的 scope 屬性 或者 @Scope 註解 來設定,例如:

  • XML 中設定作用域:<bean id="" class="" scope="prototype" />
  • 註解設定作用域: @Scope("prototype") 或者 @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)


在上述五種作用域中,實際開發中 singleton 和 prototype 是最常用的兩種,接下來將對這兩種作用域進行詳細講解。

  • singleton 作用域:singleton 是 Spring 容器預設的作用域,當一個 Bean 的作用域為 singleton 時,Spring 容器中只會存在一個共享的 Bean 例項,並且所有對 Bean 的請求,只要 id 與該 Bean 定義相匹配,就只會返回 Bean 的同一個例項。通常情況下,這種單例模式對於無會話狀態的 Bean(如 DAO 層、Service 層)來說,是最理想的選擇。
  • prototype 作用域:使用 prototype 作用域的 Bean 會在每次請求該 Bean 時都會建立一個新的 Bean 例項。因此對需要保持會話狀態的 Bean應該使用 prototype 作用域。

2、XML配置舉例

①、首先建立一個User類,程式碼如下:

/**
 * 使用者實體類
 */
public class User {
    private int userId;
    private String userName;
    private int userAge;
    private String userPwd;
    private String userAddress;

    //getter、setter省略...(這裡就不要toString方法了,因為要列印物件的地址)
}

②、在 Spring 的配置檔案我們將 scope 屬性的值設定為 prototype 多例模式,xml如下所示:

<?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">
    <!--建立一個User例項,作用域設定為prototype 多例模式-->
    <bean id="user" class="com.thr.pojo.User" scope="prototype"/>
</beans>

③、測試程式碼,這裡分別獲取了三個User物件:

/**
 * 測試程式碼
 */
public class SpringTest {
    public static void main(String[] args) {
        //1.初始化Spring容器,載入配置檔案
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
        //2.通過容器獲取例項
        User user1 =  applicationContext.getBean("user", User.class);
        User user2 =  applicationContext.getBean("user", User.class);
        User user3 =  applicationContext.getBean("user", User.class);
        //3.呼叫例項中的屬性
        System.out.println(user1);
        System.out.println(user2);
        System.out.println(user3);
    }
}

④、執行測試程式碼,檢視控制檯列印的結果:

可以很明顯的發現,這三個User物件的地址是不一樣的,說明分別建立了三個不同的User物件。

3、註解配置舉例

①、首先建立一個User類,程式碼參考上面的。

②、建立PojoConfig類,用來啟動容器和註冊Bean物件:

/**
 * 啟動容器和註冊Bean物件
 */
@ComponentScan(basePackages = "com.thr.pojo")
@Configuration
public class PojoConfig {
    public PojoConfig() {
        System.out.println("PojoConfig容器初始化成功...");
    }

    //例項化User物件
    @Bean(name = "user")
    //顯示設定單例模式
    @Scope(value = "singleton")
    public User user(){
        return new User();
    }
}

③、測試程式碼,這裡分別獲取了三個User物件,注意這裡需要使用AnnotationConfigApplicationContext類來獲取:

/**
 * 測試程式碼
 */
public class SpringTest1 {
    public static void main(String[] args) {
        //1.初始化Spring容器,通過註解載入
        ApplicationContext applicationContext = new AnnotationConfigApplicationContext(PojoConfig.class);
        //2.通過容器獲取例項
        User user1 =  applicationContext.getBean("user", User.class);
        User user2 =  applicationContext.getBean("user", User.class);
        User user3 =  applicationContext.getBean("user", User.class);
        //3.呼叫例項中的屬性
        System.out.println(user1);
        System.out.println(user2);
        System.out.println(user3);
    }
}

④、執行測試程式碼,檢視控制檯列印的結果:

由於註冊 Bean 時Scope設定為 singleton 單例模式,所以建立的多個 User 肯定是同一個,可以發現結果是一樣的。