Spring詳解(七)----Spring Bean的自動裝配(基於XML的方式)


1、自動裝配的幾種方式

上一章介紹了在XML中如何手動來配置Bean,而在Spring 容器中給我們提供了完成 Bean之間的自動裝配的功能(但是只針對對象類型的自動裝配),這樣的好處就是有助於減少編寫一個大的基於 Spring 的應用程序的 XML 配置的數量,因為在稍微大一點的項目中,一個被引用的 Bean 的 ID 改變了,那么需要修改所有引用了它的 ID 。Spring框架默認是不支持自動裝配的,可以使用Spring的配置文件中< bean >元素的 autowire 屬性為一個 bean 定義指定自動裝配模式。其中<bean>元素中的autowire屬性有5個可選值,如下:

屬性 描述
no 默認的設置,表示不啟用自動裝配,需要我們手動通過"ref"屬性手動完成裝配
byName 通過屬性名稱自動裝配,如果一個JavaBean中的屬性名稱與Bean的id 相同,則自動裝配這個Bean到JavaBean的屬性中。Spring會查找該JavaBean中所有的set方法名,獲得將set去掉並且首字母小寫的字符串,然后去Spring容器中尋找是否有此字符串名稱id 的Bean。如果有則就注入,如果沒有則注入動作將不會執行
byType 通過屬性類型自動裝配。Spring會在容器中查找JavaBean中的屬性類型與Bean的類型一致的Bean,並自動裝配這個Bean到JavaBean的屬性中,如果容器中包含多個這個類型的Bean,Spring將拋出異常。如果沒有找到這個類型的Bean,那么注入動作將不會執行
constructor 類似於byType,也是通過類型自動裝配,但是它是通過構造方法的參數類型來匹配。Spring會尋找與該JavaBean構造方法的各個參數類型相匹配的Bean,然后通過構造函數注入進來。如果在Spring容器中沒有找一個構造函數參數類型的 Bean,則會報錯
autodetect 表示在constructor和byType之間自動的選擇注入方式(spring5.x已經沒有了)。首先嘗試通過 constructor 來自動裝配,如果它不執行,則Spring 嘗試通過 byType 來自動裝配
default 由上級標簽beans的default-autowire屬性確定

2、舉例代碼

編寫User代碼:

/**
 * 用戶實體類
 */
public class User {
    private int userId;
    private String userName;
    private int userAge;
    private String userPwd;
    private String userAddress;
    //女朋友
    private GirlFriend girlFriend;

    public User() {
    }

    public User(int userId, String userName, int userAge, String userPwd,
                String userAddress, GirlFriend girlFriend) {
        this.userId = userId;
        this.userName = userName;
        this.userAge = userAge;
        this.userPwd = userPwd;
        this.userAddress = userAddress;
        this.girlFriend = girlFriend;
    }

    //getter、setter、toString方法省略......
}

編寫GirlFriend類代碼:

/**
 * GirlFriend實體
 */
public class GirlFriend {
    private String girlName;
    private int girlAge;
    private String girlHeight;

    //getter、setter、toString方法省略......
}

補充:Spring的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">
 
    <!--實例化GirlFriend-->
    <bean id="girlFriend" class="com.thr.pojo.GirlFriend">
        <property name="girlName" value="王美麗"/>
        <property name="girlAge" value="18"/>
        <property name="girlHeight" value="170"/>
    </bean>
     
    <!--實例化User-->
    <bean id="user" class="com.thr.pojo.User" autowire="byType">
        <!--注入普通值:使用 value 屬性-->
        <property name="userId" value="2020"/>
        <property name="userName" value="菜逼唐"/>
        <property name="userAge" value="18"/>
        <property name="userPwd" value="123456"/>
        <property name="userAddress" value="地球中國"/>
        <!--這里本來是手動注入GirlFriend對象,但是現在讓其自動注入,因為上面配置了 autowire="byType" -->
        <!-- <property name="girlFriend" ref="girlFriend"/> -->
    </bean>
</beans>

 測試代碼:

/**
 * 測試代碼
 */
public class SpringTest {
    public static void main(String[] args) {
        //1.初始化Spring容器,加載配置文件
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
        //2.通過容器獲取實例,getBean()方法中的參數是bean標簽中的id
        User user =  applicationContext.getBean("user", User.class);
        //3.調用實例中的屬性
        System.out.println(user.getUserName()+"-----"+user.getGirlFriend());
    }
}

3、byName裝配

byName裝配是根據屬性的名稱自動裝配,如果一個JavaBean中的屬性名稱與Bean的id 相同,則自動裝配這個Bean到JavaBean的屬性中。Spring會查找該JavaBean中所有的set方法名,獲得將set去掉並且首字母小寫的字符串,然后去Spring容器中尋找是否有此字符串名稱id 的Bean。如果有則就注入,如果沒有則注入動作將不會執行。

applicationContext.xml配置內容為:

image

運行測試代碼,查看控制台輸出:

image

可以發現根據名稱自動配置成功了,User類中girlFriend屬性自動找到了 id 為 girlFriend 的 Bean,而配置文件中如果沒有定義 id 為 girlFriend 的 Bean則會自動裝配失敗,例如,修改xml中Bean id為girlFriend1,更改后如下所示:

image

再次運行測試代碼,查看控制台輸出:

image

可以發現如果沒有找到這個bean,那么就不裝配。

4、byType裝配

byType裝配表示通過屬性類型自動裝配。Spring會在容器中查找JavaBean中的屬性類型與Bean的類型一致的Bean,並自動裝配這個Bean到JavaBean的屬性中,如果容器中包含多個這個類型的Bean,Spring將拋出異常。如果沒有找到這個類型的Bean,那么注入動作將不會執行。

我們將前面Spring配置文件中的autowire屬性修改為byType:

image

運行測試代碼,查看控制台輸出:

image

注意:使用byType首先需要保證同一類型的Bean在Spring容器中是唯一的,若不唯一則會產生歧義,Spring容器不知道選擇哪個實例注入,所以后面會報異常。

假如這里出現了兩個,那么 Spring 則不知道選擇哪個,此時會報錯:

image

運行測試代碼,查看控制台輸出:

image

所以,如果一旦選擇了byType類型的自動裝配,就必須確認配置文件中每個數據類型定義一個唯一的bean。

5、constructor裝配

constructor裝配類似於byType,也是通過類型自動裝配,但是它是通過構造方法的參數類型來匹配。Spring會尋找與該JavaBean構造方法的各個參數類型相匹配的Bean,然后通過構造函數注入進來。如果在Spring容器中沒有找一個構造函數參數類型的 Bean,則會報錯。

applicationContext.xml配置內容為:

image

運行測試代碼,查看控制台輸出:

image

constructor自動裝配具有和byType自動裝配相同的局限性,就是當發現多個Bean匹配該JavaBean構造方法的類型時,Spring不知道用哪個Bean來裝配,所以會導致裝配失敗。此外,如果一個JavaBean有多個構造方法,它們都滿足自動裝配的條件時,那么Spring也不會知道構造方法更適合使用,所以我們基本不會使用constructor裝配。

6、default裝配

default裝配表示由父級標簽beans的default-autowire屬性來配置。如果beans標簽上設置了default-autowire屬性,那么default-autowire屬性會統一配置當前beans中的所有bean的自動裝配方式。

image

  • 如果子標簽<bean>沒有單獨的設置autowire屬性,那么將采用父標簽的default-autowire屬性的模式。
  • 如果子標簽<bean>單獨設置了autowire屬性,則采用自己的模式。

7、Bean自動裝配的補充

①、上述的講到byType和constructor裝配是支持數組和強類型集合(即指定了集合元素類型)。如bean A有個屬性定義是List<Foo>類型,Spring會在容器中查找所有類型為Foo的bean,注入到該屬性。記住是Foo,不是List。另外如果集合是Map集合,那么Map的key必須是String類型,Spring會根據value的類型去匹配。例如有屬性bean A中有一個屬性為Map<String, Foo> p,容器中有bean B和C類型均為Foo,那么A實例化完成后,p屬性的值為:{"B":B的實例對象,"C":C的實例對象}。

②、雖然autowrie給我們帶來配置的便利性,但是也有缺點,比如會導致bean的關系沒那么顯而易見,所以用autowire還是ref還是需要根據項目來決定。

③、autowire-candidate:前面我們說到配置有autowire屬性的bean,Spring在實例化這個bean的時候會在容器中查找匹配的bean對autowire bean進行屬性注入,這些被查找的bean我們稱為候選bean。作為候選bean,我憑什么就要被你用,老子不給你用。所以候選bean給自己增加了autowire-candidate="false"屬性(默認是true),那么容器就不會把這個bean當做候選bean了,即這個bean不會被當做自動裝配對象。同樣,<beans/>標簽可以定義default-autowire-candidate="false"屬性讓它包含的所有bean都不做為候選bean。我的地盤我做主。

 

參考資料:


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM