Java開發學習(三)----Bean基礎設定及其作用範圍

2022-06-11 15:01:03

一、bean基礎設定

對於bean的基礎設定如下

<bean id="" class=""/>

其中,bean標籤的功能、使用方式以及id和class屬性的作用,我們通過一張圖來描述下

思考:

  • class屬效能不能寫介面如BookDao的類全名呢?

答案肯定是不行,因為介面是沒辦法建立物件的。

  • 前面提過為bean設定id時,id必須唯一,但是如果由於命名習慣而產生了分歧後,該如何解決?

在解決這個問題之前,我們需要準備下開發環境,內容如下:

二、bean的name屬性

環境準備好後,接下來就可以在這個環境的基礎上來學習下bean的別名設定,

首先來看下別名的設定說明:

步驟1:設定別名

開啟spring的組態檔applicationContext.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">
​
    <!--name:為bean指定別名,別名可以有多個,使用逗號,分號,空格進行分隔-->
    <bean id="bookService" name="service service4 bookEbi" class="com.itheima.service.impl.BookServiceImpl">
        <property name="bookDao" ref="bookDao"/>
    </bean>
​
    <!--scope:為bean設定作用範圍,可選值為單例singloton,非單例prototype-->
    <bean id="bookDao" name="dao" class="com.itheima.dao.impl.BookDaoImpl"/>
</beans>

說明:Ebi全稱Enterprise Business Interface,翻譯為企業業務介面

步驟2:根據名稱容器中獲取bean物件
public class AppForName {
    public static void main(String[] args) {
        ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
        //此處根據bean標籤的id屬性和name屬性的任意一個值來獲取bean物件
        BookService bookService = (BookService) ctx.getBean("service4");
        bookService.save();
    }
}
步驟3:執行程式

測試結果為:

注意事項:

  • bean依賴注入的ref屬性指定bean,必須在容器中存在

  • 如果不存在,則會報錯,如下:

    這個錯誤大家需要特別關注下:

    獲取bean無論是通過id還是name獲取,如果無法獲取到,將丟擲異常NoSuchBeanDefinitionException

    遇到這樣的問題通常檢查名稱是否寫錯

三、bean作用範圍scope設定

關於bean的作用範圍是bean屬性設定的一個重點內容。看到這個作用範圍,我們就得思考bean的作用範圍是來控制bean哪塊內容的?

我們先來看下bean作用範圍的設定屬性:

3.1 驗證IOC容器中物件是否為單例

驗證思路

同一個bean獲取兩次,將物件列印到控制檯,看列印出的地址值是否一致。

具體實現
  • 建立一個AppForScope的類,在其main方法中來驗證

    public class AppForScope {
        public static void main(String[] args) {
            ApplicationContext ctx = new 
                ClassPathXmlApplicationContext("applicationContext.xml");
    ​
            BookDao bookDao1 = (BookDao) ctx.getBean("bookDao");
            BookDao bookDao2 = (BookDao) ctx.getBean("bookDao");
            System.out.println(bookDao1);
            System.out.println(bookDao2);
        }
    }
  • 列印,觀察控制檯的列印結果

  • 結論:預設情況下,Spring建立的bean物件都是單例的

獲取到結論後,問題就來了,那如果我想建立出來非單例的bean物件,該如何實現呢?

3.2 設定bean為非單例

在Spring組態檔中,設定scope屬性來實現bean的非單例建立

  • 在Spring的組態檔中,修改<bean>的scope屬性

    <bean id="bookDao" name="dao" class="com.itheima.dao.impl.BookDaoImpl" scope=""/>
  • 將scope設定為singleton

    <bean id="bookDao" name="dao" class="com.itheima.dao.impl.BookDaoImpl" scope="singleton"/>

    執行AppForScope,列印看結果

  • 將scope設定為prototype

    <bean id="bookDao" name="dao" class="com.itheima.dao.impl.BookDaoImpl" scope="prototype"/>

    執行AppForScope,列印看結果

  • 結論,使用bean的scope屬性可以控制bean的建立是否為單例:

    • singleton預設為單例

    • prototype為非單例

3.3 scope使用後續思考

介紹完scope屬性以後,我們來思考幾個問題:

  • 為什麼bean預設為單例?

    • bean為單例的意思是在Spring的IOC容器中只會有該類的一個物件

    • bean物件只有一個就避免了物件的頻繁建立與銷燬,達到了bean物件的複用,效能高

  • bean在容器中是單例的,會不會產生執行緒安全問題?

    • 如果物件是有狀態物件,即該物件有成員變數可以用來儲存資料的,

    • 因為所有請求執行緒共用一個bean物件,所以會存線上程安全問題。

    • 如果物件是無狀態物件,即該物件沒有成員變數沒有進行資料儲存的,

    • 因方法中的區域性變數在方法呼叫完成後會被銷燬,所以不會存線上程安全問題。

  • 哪些bean物件適合交給容器進行管理?

    • 表現層物件 serviceImpl

    • 業務層物件 service

    • 資料層物件 dao

    • 工具物件 util

  • 哪些bean物件不適合交給容器進行管理?

    • 封裝範例的域物件,因為會引發執行緒安全問題,所以不適合。