Spring(一)- 初始 + DI+scope

来源:https://www.cnblogs.com/xiaoqigui/archive/2022/08/25/16625420.html
-Advertisement-
Play Games

1、獲取bean實例的三種方式 1.1 id 屬性 1.1.1 jar <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <spring.version>4.3.18.RELEASE</sp ...


1、獲取bean實例的三種方式

1.1 id 屬性

1.1.1 jar

Spring架構圖
<properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <spring.version>4.3.18.RELEASE</spring.version>
    <lombok.version>1.16.18</lombok.version>
    <junit.version>4.11</junit.version>

</properties>

<dependencies>
    <!-- spring-beans begin -->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-beans</artifactId>
        <version>${spring.version}</version>
    </dependency>
    <!-- spring-beans end -->

    <!-- spring-core begin -->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-core</artifactId>
        <version>${spring.version}</version>
    </dependency>
    <!-- spring-core end -->

    <!-- spring-context begin -->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context</artifactId>
        <version>${spring.version}</version>
    </dependency>
    <!-- spring-context end -->

    <!-- spring-expression begin -->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-expression</artifactId>
        <version>${spring.version}</version>
    </dependency>
    <!-- spring-expression end -->

</dependencies>

1.1.2 application.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">

    <!-- 基於spring的核心配置文件方式,手動配置一個bean,放到spring的容器中 -->
    <bean id="userOne" class="com.kgc.spring.bean.User">
        <property name="nickName" value="kh96_spring_one"></property>
    </bean>
</beans>

<bean>標簽:定義一個實例對象,會自動被創建 並 交給spring容器進行管理:

  • id 屬性:被spring容器進行管理的實例的 唯一標識,整個容器中,只能是唯一的(不可重覆);

  • class屬性:指定創建當前實例對象的類型(全類名),spring底層是使用的 反射機制 ,根據指定的目標類型,創建目標實例(必須有 空參構造)

  • <property>子標簽:給當前創建對象的屬性值

    • name:指定對象的屬性名
    • value: 給屬性賦值

1.1.3 測試

@Test
public void testSpringPrimer(){
    //1.創建spring的核心容器對象(引用上下文對象),解析spring的核心配置文件,將文件中的bean標簽進行實例化(創建對象並賦值)
    ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");

    //2. 寫法一: 從容器中獲取實例對象,根據核心配置文件中,配置的bean標簽的id屬性值
    //            不足:強制轉化,容易出現轉換錯誤
    User userOne = (User) context.getBean("userOne");
    
    userOne.sayHello();

    //對比以前創建對象的寫法(對象必須手動new創建,並手動賦值)
    User userOld = new User();
    userOld.setNickName("kh96_old");
    userOld.sayHello();
     
}

1.1.4 總結

通過id屬性,獲取實例對象後需要強制轉換,容易出現強制轉化錯誤

1.2 class 屬性

1.2.1 測試

//寫法二:從容器中獲取實例對象,根據核心配置文件中,配置的bean標簽的class屬性指定的目標類型
User userTwo = context.getBean(User.class);

userTwo.sayHello();

1.2.2 總結

不足:如果存在同類型的多個實例,會報異常

1.2.2.1 application.xml

當用多個同類型的實例:

...
<bean id="userOne" class="com.kgc.spring.bean.User">
    <property name="nickName" value="kh96_spring_one"></property>
</bean>

<!-- Configuration problem: Bean name 'userOne' is already used in this <beans> element -->
<bean id="userTwo" class="com.kgc.spring.bean.User">
    <property name="nickName" value="kh96_spring_two"></property>
</bean>
...
1.2.2.2 測試
User userTwo = context.getBean(User.class);

會發生異常:

NoUniqueBeanDefinitionException: No qualifying bean of type 'com.kgc.spring.bean.User' available: expected single matching bean but found 2: userOne,userTwo

主要原因是由於只用class屬性去獲取實例,但是有多個相同類型的實例,所以無法確定你要獲取的是哪一個

1.3 id 屬性 和 class 屬性 (推薦)

1.3.1 測試

//寫法三:從容器中獲取實例對象,根據配置文件中,配置的bean標簽的id屬性值和class屬性指定的目標類型
 User userTwoThree = context.getBean("userTwo", User.class);

1.3.2 總結

能夠確定唯一實例,推薦使用;

1.4 id 不能重覆註意點

配置文件中的id必須是唯一的;

如果id不唯一:兩個id一樣的實例

...
<bean id="userOne" class="com.kgc.spring.bean.User">
    <property name="nickName" value="kh96_spring_one"></property>
</bean>
<bean id="userOne" class="com.kgc.spring.bean.User">
    <property name="nickName" value="kh96_spring_one"></property>
</bean>
...

報錯:

BeanDefinitionParsingException: Configuration problem: Bean name 'userOne' is already used in this <beans> element

提示 id 為 userOne 的實例已經存在;

1.5 實例化時機

初始化spring的容器對象時,會將核心配置文件中所有的bean實例化,不是使用哪個,創建哪個;

2、DI

IOC(控制反轉是一種思想),DI是IOC的一種實現方式;

2.1 set 方式註入

2.1.1 實體

@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {

    //用戶昵稱
    //普通參數
    private String nickName;

    //私家車
    //實體參數
    private Car car;

    //喜歡的書
    //數組參數
    private String[] books;

    //愛好
    //list集合參數
    private List<String> hobbies;

    //喜歡的游戲
    //set 集合
    private Set<String> games;

    //卡包
    //map參數
    private Map<String,String> cards;

    //在校信息
    //properties參數
    private Properties info;

    //是否有女朋友 (主要是演示賦值為null,其他類型都可以)
    //空參數註入
    private Boolean wife;

}

2.1.2 參數 註入

...
<!-- 不同類型參數的set註入 -->
<bean id="user01" class="com.kgc.spring.bean.User">
    <!-- 1.普通參數 註入 -->
    <property name="nickName" value="小氣鬼"></property>
     <!-- 2.實體參數 註入 -->
    <!-- 2.1 實體參數 註入方式一 外部引入 ref -->
    <!--  <property name="car" ref="carOne"></property>-->
    <property name="car">
        <!-- 2.2 實體參數註入方式二 內部註入 <bean> -->
        <bean class="com.kgc.spring.bean.Car">
            <property name="brand" value="Bmw325"></property>
            <property name="factory" value="華晨"></property>
            <property name="price" value="300000"></property>
        </bean>
    </property>
    <!-- 3.數組參數 註入 -->
    <property name="books">
        <array>
            <value>紅樓夢</value>
            <value>水滸傳</value>
            <value>三國演義</value>
            <value>西游記</value>
        </array>
    </property>
    <!-- 4.list集合參數 -->
    <property name="hobbies" >
        <list>
            <value>跑步</value>
            <value>尤克裡里</value>
            <value>敲代碼</value>
        </list>
    </property>
    <!-- 5.set 集合參數 註入 -->
    <property name="games">
        <set>
            <value>唱歌</value>
            <value>跳舞</value>
            <value>喝酒</value>
        </set>
    </property>
    <!-- 6.map參數 -->
    <property name="cards">
        <map>
            <entry key="身份證" value="1212121212121212"></entry>
            <entry key="銀行卡" value="1111111111111111"></entry>
        </map>
    </property>
    <!-- 7.properties參數 -->
    <property name="info">
        <props>
            <prop key="學號">123456</prop>
            <prop key="性別">男</prop>
            <prop key="姓名">化羽</prop>
        </props>
    </property>
    <!-- 8.空參數註入 -->
    <property name="wife">
        <null></null>
    </property>
</bean>


<bean id="carOne" class="com.kgc.spring.bean.Car">
    <property name="brand" value="Bmw325"></property>
    <property name="factory" value="華晨"></property>
    <property name="price" value="300000"></property>
</bean>
...

2.1.3 測試

@Test
public void testPramsDI(){
    User user01 = context.getBean("user01", User.class);
    //輸入對象詳情
    System.out.println(user01);
}

輸出結果:

User(
     nickName=小氣鬼, 
     car=Car(brand=Bmw325, factory=華晨, price=300000.0), 
     books=[紅樓夢, 水滸傳, 三國演義, 西游記], 
     hobbies=[跑步, 尤克裡里, 敲代碼], 
     games=[唱歌, 跳舞, 喝酒], 
     cards={身份證=1212121212121212, 銀行卡=1111111111111111}, 
     info={學號=1913001072, 性別=男, 姓名=化羽}, 
     wife=null
    )

2.2 Constructor 構造器註入

2.2.1 按照預設順序 註入

2.2.1.1 參數註入
<!--
實體構造方法:Car(String brand, String factory, Double price) 
-->
<!--  構造器註入:通過構造方法,預設是按照構造方法的參數定義順序賦值  -->
<bean id="carTwo" class="com.kgc.spring.bean.Car">
    <constructor-arg value="AudiA4"></constructor-arg>
    <constructor-arg value="一汽"></constructor-arg>
    <constructor-arg value="320000"></constructor-arg>
</bean>
2.2.1.2 測試
@Test
public void testSpringDIConstructor(){
    Car carTwo = context.getBean("carTwo", Car.class);

    //輸出對象詳情
    System.out.println(carTwo);
}

2.2.2 根據 參數的下標 和 類型 註入

2.2.2.1 參數註入
<!-- 根據構造器中參數的下標 和 類型 賦值 -->
<bean id="carThree" class="com.kgc.spring.bean.Car">
    <constructor-arg index="0" value="BenzC200"></constructor-arg>
    <constructor-arg index="1" value="北京"></constructor-arg>
    <constructor-arg index="2" type="java.lang.Double" value="350000"></constructor-arg>
<!-- 
如果參數列表中,該類型的參數只用一個,也可以只指定參數類型
<constructor-arg type="java.lang.Double" value="350000"></constructor-arg> 
-->
</bean>
2.2.2.2 測試
@Test
public void testSpringDIConstructor2(){
    Car carTwo = context.getBean("carThree", Car.class);

    //輸入對象詳情
    System.out.println(carTwo);
}

2.3 自定義 實體工廠bean

自定義實體工廠bean ,必須實現FactoryBean介面

普通bean 與 工廠bean 的區別:

  • 普通 bean:在配置文件中定義 bean 類型 就是 返回類型
  • 工廠 bean:在配置文件定義 bean 類型返回類型 不一樣

2.3.1 返回bean

@Data
@ToString
public class Car {
    /*
     品牌
     */
    private String brand;

    /*
    廠商
     */
    private String factory;

    /*
    價格
     */
    private Double price;
}

2.3.2 實體工廠 bean

  • spring容器初始化時,創建當前工廠bean的實例對象,但是真實返回不是當前類的實例對象而是當前類的實例對象返回的目標實例對象(自定義);
  • 作用:可以在程式中,實現自定義創建實例(還可以增加業務邏輯處理),放入容器;
  • 存在的原因:spring框架對外開放了一個入口,可以讓其他的開發人員參與到spring底層創建bean的實例過程中去給整合其他框架使用的,比如mybatis;
public class CarFactoryBean implements FactoryBean<Car> {
    @Override
    public Car getObject() throws Exception {
        System.out.println("通過CarFactoryBean的實例對象的getObject方法:返回一個自定義的car的實例");
        return new Car("Byd唐","南京",2500000.0);
    }

    @Override
    public Class<?> getObjectType() {
        //指定給Object方法返回的目標類型
        return Class.class;
    }

    @Override
    public boolean isSingleton() {
        //是否單例
        return false;
    }
}

2.3.3 工廠bean容器中添加自定義實例對象

...
<!-- 使用工廠bean容器,添加自定義實例對象 -->
<bean id="carFactoryBean" class="com.kgc.spring.bean.CarFactoryBean"></bean>
...

2.3.4 測試

@Test
public void testSpringFactoryBean(){
    //從容器中獲取工廠bean的實例對象
    Car car1 = context.getBean("carFactoryBean", Car.class);
    Car car2 = context.getBean("carFactoryBean", Car.class);

    //輸出對象詳情
    System.out.println(car 1); 
    //在容器中添加的實例是  CarFactoryBean 類型,返回的是 
    //Car(brand=Byd唐, factory=南京, price=2500000.0)
    System.out.println("car1 == car2 : " + ( car1 == car2)); 
    //false  說明工廠bean是多例的

}

3、scope作用域

  • singleton 單例 (預設) 容器初始化之前創建;
  • prototype 多例 (手動設置) 使用到的時候才創建;

3.1 singleton 單例

這裡區別於整個程式運行期間有且只有唯一的實例(單例模式-懶漢和餓漢);

容器中bean的單例不是指當前類的實例在容器中,只有唯一的實例,而是當創建bean的實例時,此實例是單例(容器內唯一),但是同一個類的實例,容器中可以創建多個每個都是單例的

3.1.1 配置bean

<!-- scope="singleton" 不寫預設也是單例的  -->
<bean id="busTwo" class="com.kgc.spring.bean.Bus" scope="singleton">
    <property name="brand" value="金龍2"></property>
    <property name="factory" value="廈門2"></property>
    <property name="price" value="1200000"></property>
</bean>

3.1.2 測試

@Test
public void testScopeSingleton(){
    
    //從容器中,獲取Bus的實例對象
    Bus busThree = context.getBean("busTwo", Bus.class);
    Bus busFour = context.getBean("busTwo", Bus.class);

    System.out.println(busThree);
    System.out.println(busFour);

    System.out.println("singleton busThree == busFour:"+(busThree == busFour));
	//true
}

3.2 prototype 多例

多例:prototype,不是spring容器中的預設作用,需要單獨指定

spring容器創建時,不會自動創建指定作用域為多例的bean的實例,而是每次通過getBean方法獲取bean的實例,才會創建bean的實例

3.2.1 配置bean

<!--  scope="prototype" 多例需要手動設置 -->
<bean id="busThree" class="com.kgc.spring.bean.Bus" scope="prototype">
    <property name="brand" value="中通3"></property>
    <property name="factory" value="山東3"></property>
    <property name="price" value="1200000"></property>
</bean>

3.2.2 測試

@Test
public void testScopePrototype(){
    Bus busOne = context.getBean("busThree", Bus.class);
    Bus busTwo = context.getBean("busThree", Bus.class);

    //輸入詳情
    System.out.println(busOne);
    System.out.println(busTwo);

    System.out.println("prototype busOne == busTwo:"+(busOne == busTwo));
    //false

}

您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • Silver Efex Pro是您將使用的最先進的黑白照片插件。憑藉其獨特的演算法以及一系列用於亮度,對比度和放大白色等變化的工具和調整,Silver Efex Pro 3可以藉助最全面的暗房風格控制項來掌握黑白攝影藝術,為大家帶來了20種不同的黑白傳奇電影效果。 詳情:Silver Efex Pro ...
  • 想要全方位的實現HDR增強效果小編推薦使用HDR Efex Pro 2 Mac版,這是一款一款全新的高動態(HDR)成像解決方案,內置33種HDR效果,用戶可在右側HDR進行細節微調,強大簡便。 詳情:HDR Efex Pro 2 for mac(HDR濾鏡軟體) Hdr Efex Pro2是一款全 ...
  • 很多小伙伴不知道Color Efex Pro 4是用來幹嘛的,小編給大家介紹一下,Color Efex Pro 4 for Mac全球最全面,最有創意的濾鏡組,用於色彩校正,潤飾和應用最令人驚嘆和最富想象力的攝影效果,釋放最大的創造力和想象力。 詳情:Color Efex Pro 4 for Mac ...
  • 1. 關聯關係 1.1 關聯關係概念說明 表與表之間的關係 : 1 對 1 1對多 多對多關係 ,通過主外鍵來實現。 外鍵在多的一方。比如員工和部門: 1個員工對應一個部門,一個部門可以有多個員工 要將表與表之間的關係:映射稱為 類與類之間的關係(準確的說應該是 對象和對象之間的關係 ) 一對一 夫 ...
  • 學習Stream的目的 函數式編程漸漸變成主流,為了看懂同事的代碼。 相對於傳統的編程方式,代碼更為簡潔清晰易懂。 使得併發編程變得如此簡單。 有效的避免了代碼嵌套地獄。(見樣例) if (條件1) { if (條件2) { if (條件3) { // 再嵌套下去都快見到Diablo了。 } } } ...
  • 目錄 一.OpenGL 波浪特效效果演示 1.原始圖片 2.效果演示 二.OpenGL 波浪特效源碼下載 三.猜你喜歡 零基礎 OpenGL ES 學習路線推薦 : OpenGL ES 學習目錄 >> OpenGL ES 基礎 零基礎 OpenGL ES 學習路線推薦 : OpenGL ES 學習目 ...
  • ##redis是什麼? Redis(Remote Dictionary Server ),即遠程字典服務,是一個開源的使用ANSI C語言編寫、支持網路、可基於記憶體亦可持久化的日誌型、Key-Value資料庫,並提供多種語言的API。 redis是一個key-value存儲系統。和Memcached ...
  • Java集合09 18.TreeSet 元素無序:插入順序和輸出順序不一致 可以按照一定的規則進行排序,具體排序方式取決於構造方法: TreeSet () :根據其元素的自然排序進行排序 TreeSet (Comparator comparator) :根據指定的比較器進行排序 沒有帶索引的方法,所 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...