Spring 當中的Bean 作用域

Rainbow-Sea發表於2024-04-29

Spring 當中的Bean 作用域

@

目錄
  • Spring 當中的Bean 作用域
  • 每博一文案
  • 1. Spring6 當中的 Bean的作用域
    • 1.2 singleton 預設
    • 1.3 prototype
    • 1.4 Spring 中的 bean 標籤當中scope= 屬性其他的值說明
    • 1.5 自定義作用域,一個執行緒一個 Bean
  • 2. 總結:
  • 3. 最後:


每博一文案

青年,青年!無論受怎樣的挫折和打擊,都要咬著牙關挺住,因為你們完全有機會重建生活;只要不灰心喪氣,每一次挫折就只不過是通往新境界的一塊普通絆腳石,而絕不會置人於死命
									_____路遙《平凡的世界》
飛機上鄰座的姐姐
獨自一人坐飛機去見異地的男友
異地戀赤誠的人好像越來越少
我不自覺地問她
如果以後分手了不會覺得可惜麼
她一邊低頭和男友報備自己落座了
一邊回答說“我不是確認了不會分手才去愛他的,我恰恰是因為確定了我們有可能會分手才更要
用力去愛他的,更何況,人是用來擁有的,不是嗎”
								———————《網友評論》

1. Spring6 當中的 Bean的作用域

1.2 singleton 預設

預設情況下,Spring的IoC容器建立的Bean物件是單例的。

我們來檢驗一下:

首先,方便大家處理,下面明確出對應相關的 maven配置資訊pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.rainbowsea</groupId>
    <artifactId>spring6-007-circular-dependency</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>jar</packaging>

    <properties>
        <maven.compiler.source>17</maven.compiler.source>
        <maven.compiler.target>17</maven.compiler.target>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>6.0.11</version>
        </dependency>


        <!-- junit4 -->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.13.2</version>
            <scope>test</scope>
        </dependency>
    </dependencies>

</project>

對應配置的 bean 的類是 User 這個類 ,為了方便辨析,簡單明瞭,這個 類,就不設定屬性了。就是一個空空的類。

package com.rainbowsea.spirngBean;

public class User {
    public User() {
        System.out.println("User() 的無引數構成方法");
    }
}

配置 Spring框架當中的xml 配置檔案,讓 Spring 知道我們的 User 這個類,並進行管理

在這裡插入圖片描述

<?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 name="user" class="com.rainbowsea.spirngBean.User"></bean>
</beans>

下面編寫測試:程式碼,進行一個測試,驗證,Spring 預設是否是 單例的 。這裡我們啟動多執行緒,進行一個測試

在這裡插入圖片描述

package com.ranbowsea.test;

import com.rainbowsea.spirngBean.User;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class testScope {

    @Test
    public void test01() {
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring6.xml");
        User user = applicationContext.getBean("user", User.class);
        User user1 = applicationContext.getBean("user", User.class);
        System.out.println(user);
        System.out.println(user1);

        // 啟動執行緒
        new Thread(new Runnable() {
            @Override
            public void run() {
                User user2 = applicationContext.getBean("user", User.class);
                User user3 = applicationContext.getBean("user", User.class);
                System.out.println(user2);
                System.out.println(user3);
            }
        }).start();
    }
}

在這裡插入圖片描述

從結果上看:

  1. 無參構造方法僅僅只被呼叫了一次
  2. 四個user物件,的地址是一樣的

說明:無論是執行多少次,applicationContext.getBean ,還是啟動多個執行緒,都是同一個User物件. 是單例的

這個物件在什麼時候建立的呢?可以為SpringBean提供一個無引數構造方法,測試一下,如下:

在這裡插入圖片描述

從結果上來看:是在 new ClassPathXmlApplicationContext() 的時候就已經,執行了構造方法(Bean物件的建立是在初始化Spring上下文的時候就完成的。)

其中: singletonSpring框架 預設的,也是單例的。

我們可以使用:可以在bean標籤中指定 scope屬性的值為 singleton 。我們測試如下。

在這裡插入圖片描述

<?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 name="user" class="com.rainbowsea.spirngBean.User" scope="singleton"></bean>
</beans>

在這裡插入圖片描述

透過測試得知,沒有指定scope屬性時,預設是singleton單例的。

1.3 prototype

如果想讓Spring的Bean物件以多例 的形式存在,可以在bean標籤中指定 scope屬性的值為:prototype,這樣Spring會在每一次執行getBean()方法的時候建立Bean物件,呼叫幾次則建立幾次。

在這裡插入圖片描述

在這裡插入圖片描述

<?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 name="user" class="com.rainbowsea.spirngBean.User" scope="prototype"></bean>
</beans>

我們來是:用 User 這個類進行測試,使用:

在這裡插入圖片描述

在這裡插入圖片描述


import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class testScope {
    @Test
    public void test() {
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring6.xml");
        User user = applicationContext.getBean("user", User.class);
        User user1 = applicationContext.getBean("user", User.class);
        System.out.println(user);
        System.out.println(user1);

    }
}

從結果上看:

1.呼叫了兩次無引數構成方法()

2.是兩個不同的 user物件的地址

啟動多個執行緒,也是會存在多個,user物件的地址的,同時呼叫多次無引數構成方法()——> 是多例 的。 不像 singleton(預設)的那樣是無論是執行多少次,applicationContext.getBean ,還是啟動多個執行緒,都是同一個User物件單例的。

在這裡插入圖片描述


import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class testScope {
    @Test
    public void test() {
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring6.xml");
        User user = applicationContext.getBean("user", User.class);
        User user1 = applicationContext.getBean("user", User.class);
        System.out.println(user);
        System.out.println(user1);

        // 啟動多執行緒
        new Thread(new Runnable() {
            @Override
            public void run() {
                User user2 = applicationContext.getBean("user", User.class);
                User user3 = applicationContext.getBean("user", User.class);
                System.out.println(user2);
                System.out.println(user3);
            }
        }).start();

    }


}

1.4 Spring 中的 bean 標籤當中scope= 屬性其他的值說明

scope屬性的值不止兩個,它一共包括8個選項:

      1. singleton:預設的,單例。
      2. prototype:原型。每呼叫一次getBean()方法則獲取一個新的Bean物件。或每次注入的時候都是新物件。
      3. request:一個請求對應一個Bean。僅限於在WEB應用中使用
      4. session:一個會話對應一個Bean。僅限於在WEB應用中使用
      5. global sessionportlet應用中專用的。如果在Servlet的WEB應用中使用global session的話,和session一個效果。(portlet和servlet都是規範。servlet執行在servlet容器中,例如Tomcat。portlet執行在portlet容器中。)
      6. application:一個應用對應一個Bean。僅限於在WEB應用中使用。
      7. websocket:一個websocket生命週期對應一個Bean。僅限於在WEB應用中使用。
      8. 自定義scope:很少使用。

特殊說明: 如果大家,進行了一個實踐測試程式碼,可能會發現,IDE工具,僅僅只提示了 scope屬性值的兩個值(singleton,prototype)。就算我們自己手動敲出了其他的值,也是會報 。如下圖所示:

在這裡插入圖片描述

在這裡插入圖片描述

哈哈哈,這個IDE不給我們提示就算了,還給我們報錯。

其實這個並不是IDE工具的問題,而是,我們其他的對應的scope其他屬性的值,是需要在特定的情況下才有用的。比如:我們這裡的 request 是需要在 web 專案當中才是有用的 ,所以 IDE才給我們來了這麼一個錯誤——》爆紅了。

我們可以,在 pom.xml 專案配置檔案上,加上一個web 框架,比如:這裡我們加上SpringMVC 就可以了。試試

在這裡插入圖片描述

        <!-- https://mvnrepository.com/artifact/org.springframework/spring-webmvc -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>5.3.18</version>
        </dependency>

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.rainbowsea</groupId>
    <artifactId>spring6-007-circular-dependency</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>jar</packaging>

    <properties>
        <maven.compiler.source>17</maven.compiler.source>
        <maven.compiler.target>17</maven.compiler.target>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>6.0.11</version>
        </dependency>


        <!-- junit4 -->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.13.2</version>
            <scope>test</scope>
        </dependency>
        <!-- https://mvnrepository.com/artifact/org.springframework/spring-webmvc -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>5.3.18</version>
        </dependency>

    </dependencies>

</project>

在這裡插入圖片描述

1.5 自定義作用域,一個執行緒一個 Bean

接下來咱們自定義一個Scope,關於執行緒級別的Scope,

作用:在同一個執行緒中,獲取的Bean都是同一個。跨執行緒則是不同的物件。

  • 第一步:自定義Scope。(實現Scope介面)

  • spring內建了執行緒範圍的類:org.springframework.beans.factory.config.CustomScopeConfigurer,和 org.springframework.context.support.SimpleThreadScope可以直接用。

    • 第二步:將自定義的Scope註冊到Spring容器中。

在這裡插入圖片描述

<bean class="org.springframework.beans.factory.config.CustomScopeConfigurer">
  <property name="scopes">
    <map>
      <entry key="myThread">
        <bean class="org.springframework.context.support.SimpleThreadScope"/>
      </entry>
    </map>
  </property>
</bean>
<?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">

<!-- 自定義一個 scope屬性值:作用:在同一個執行緒中,獲取的Bean都是同一個。跨執行緒則是不同的物件。-->
    <bean class="org.springframework.beans.factory.config.CustomScopeConfigurer">
        <property name="scopes"> <!-- set 注入,為該類當中的 name 屬性賦值-->
            <map> <!-- map集合 注入,為該類當中的 key 屬性賦值,也就是我們自定義的 scope的屬性值的名字-->
                <entry key="myThread">
                    <bean class="org.springframework.context.support.SimpleThreadScope"/>
                </entry>
            </map>
        </property>
    </bean>



    <bean name="user" class="com.rainbowsea.spirngBean.User" scope="myThread"></bean>
</beans>

我們還是使用 User 這個類,作為 Bean 進行一個測試。

在這裡插入圖片描述

啟動多個執行緒,處理。

在這裡插入圖片描述


import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class testScope {
    @Test
    public void test() {
        // 第一個執行緒
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring6.xml");
        User user = applicationContext.getBean("user", User.class);
        User user1 = applicationContext.getBean("user", User.class);
        System.out.println(user);
        System.out.println(user1);

        // 啟動多執行緒
        // 第二個執行緒
        new Thread(new Runnable() {
            @Override
            public void run() {
                User user2 = applicationContext.getBean("user", User.class);
                User user3 = applicationContext.getBean("user", User.class);
                System.out.println(user2);
                System.out.println(user3);
            }
        }).start();

    }
}

從結果上,我們可以看出:

一個執行緒,呼叫了一次無參構造方法(),生產一個物件。

成功實現了。在同一個執行緒中,獲取的Bean都是同一個。跨執行緒則是不同的物件。

2. 總結:

  1. 預設情況下,Spring的IoC容器建立的Bean物件是單例的。預設是singleton(單例的)
  2. 可以在bean標籤中指定scope屬性的值為:**prototype(多例),預設是singleton(單例的) **
  3. 同時要注意:scope屬性的值不止兩個,它一共包括8個選項:,其他的要在特定的配置下,才能使用,例如:request和session 要是在 web 框架才可以使用。

3. 最後:

“在這個最後的篇章中,我要表達我對每一位讀者的感激之情。你們的關注和回覆是我創作的動力源泉,我從你們身上吸取了無盡的靈感與勇氣。我會將你們的鼓勵留在心底,繼續在其他的領域奮鬥。感謝你們,我們總會在某個時刻再次相遇。”

在這裡插入圖片描述

相關文章