1. 程式人生 > 實用技巧 >Spring詳解(九)----Spring Bean的自動裝配(基於註解的方式【推薦】)

Spring詳解(九)----Spring Bean的自動裝配(基於註解的方式【推薦】)

1、使用@Autowired註解自動裝配

上一章提到使用@Value註解只能裝配普通值,是不能裝配物件的,所以這章我們來介紹使用註解自動裝配物件,需要使用到@Autowired註解:

  • @Autowired:它預設是按byType進行匹配,可以用於修飾類成員變數(欄位)、Setter 方法、建構函式,甚至普通方法,但是前提是方法必須有至少一個引數。

我們在實際的開發中基本都會使用註解來對物件屬性完成自動裝配,因為這樣可以減少配置的複雜度,所以@Autowired非常的重要!

①、作用於類的成員變數(欄位)(最常用)

---User類:

@Component(value = "user")
public class User {
    @Value(value = "2020")
    private int userId;
    @Value(value = "是菜逼唐")
    private String userName;
    @Value(value = "20")
    private int userAge;
    @Value(value = "123456")
    private String userPwd;
    @Value(value = "地球中國北京")
    private String userAddress;

    //這裡使用@Autowired註解自動注入
    @Autowired
    private GirlFriend girlFriend;

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

---GirlFriend類:

@Component
public class GirlFriend {
    @Value("王美麗")
    private String girlName;
    @Value("18")
    private int girlAge;
    @Value("170")
    private String girlHeight;

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

---測試程式碼(掃描元件註解參考上一章):

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

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


②、作用於Setter方法和作用於建構函式。這兩種方式實現的效果和上面的效果是一模一樣的。

1)、作用於Setter方法

2)、作用於建構函式

注意:如果已經使用註解完成了初始化工作,那麼則不能再建立該引數的構造方法了,比如我們使用了@Value註解初始化userName屬性,那麼則就不能再建立userName屬性的構造方法了。

可以明顯的分析,後面兩種方式的可讀性並不高,所以一般都推薦使用第一種方式,作用於類的成員變數。


補充1:@Autowired註解中有個屬性required,這個屬性是一個boolean型別,為true(預設)表示注入bean的時候該bean必須存在,不然就會注入失敗,但程式不報錯 。為 false 表示注入bean的時候如果bean存在,就注入成功,如果沒有就忽略跳過,啟動時不會報錯!但是不能直接使用,因為bean為NULL!

例如我將GirlFriend類的@Component註解給註釋掉,並且把User類中的@Autowired註解的屬性required設定為false。

----------------------------------------

通過執行的結果可以發現注入失敗了。


補充2:@Autowired註解並不是完全按照byType進行匹配。而是預設先按byType進行匹配,如果發現找到多個bean,則又按照byName方式進行匹配,如果還有多個,則報出異常。動手能力強的可以自己去實踐一遍,我自己是去驗證過的。

2、@Autowired自動裝配的歧義性

由於@Autowired註解是根據型別來自動裝配的,所以肯定會存在有多個相同型別的bean,而Spring IOC容器卻不知要選擇哪一個的情況,此時就產生了歧義性,那麼我們怎麼來解決呢?Spring中給我們提供了@Primary和@Qualifier這兩個註解。

  • @Primary:表示優先使用該註解標誌的bean。實際開發中不實用。
  • @Qualifier:表示當容器中存在多個相同型別的bean時,使用這個註解可以根據bean的名字來選擇注入哪個bean,推薦使用這種方式。

3、與@Autowired類似的註解@Resource

@Resource 註解相當於@Autowired,它們兩個都是用來實現依賴注入的。只是@AutoWried預設按byType自動注入,而@Resource預設按byName自動注入。而且@Resource只能處理setter注入(包括欄位)。@Resource有兩個重要屬性,分別是name和type,其中name屬性相當於@Qualifier,type相當於根據型別配置。spring將name屬性解析為bean的名字,而type屬性則被解析為bean的型別。所以如果使用name屬性,則使用byName的自動注入策略,如果使用type屬性則使用byType的自動注入策略。如果都沒有指定,則通過反射機制使用byName自動注入策略。表面上我們說@Resource預設按byName自動注入,其實如果按名稱查詢不到匹配的bean時,最後會按byType進行自動注入,@Resource依賴注入時查詢bean的規則如下:

  • 如果不指定name屬性,也不指定type屬性,則自動按byName方式進行查詢。如果沒有找到符合的bean,則回退為一個原始型別進行進行查詢,如果找到就注入。
  • 只是指定了@Resource註解的name屬性,則只能按name後的名字去bean元素裡查詢有與之相等的name屬性的bean,如果找不到則會丟擲異常。
  • 只指定@Resource註解的type屬性,則從上下文中找到型別匹配的唯一bean進行裝配,找不到或者找到多個,都會丟擲異常。
  • 既指定了@Resource的name屬性又指定了type,則從Spring上下文中找到唯一匹配的bean進行裝配,找不到則丟擲異常。


補充:但是我好像聽說這個註解在Java11中被刪除了,也不知道是不是真的,如果是真的還是慎用!然後我去查了一下JDK11的官方文件,確實JDK11將javax.annotation這個包移除了,如果想繼續使用可以通過maven或者其他方式匯入。

<dependency>
    <groupId>javax.annotation</groupId>
    <artifactId>javax.annotation-api</artifactId>
    <version>1.3.2</version>
</dependency>

如果這個依賴無法使用,可以去maven倉庫自行查詢。

4、@Autowired和@Resource的區別

相同點:

  • 二者均可以用來注入bean,都可以用在欄位上或者方法上

不同點:

  • @Autowired是屬於Spring框架的,而@Resource屬於J2EE。
  • @Autowired預設按byType進行裝配,可以結合@Qualifier使用按名稱裝配,如果發現找到多個bean,則又按照byName方式進行匹配,如果還有多個,則報出異常。
  • @Resource預設按byName進行裝配,名稱可以通過name屬性進行指定,如果沒有指定name屬性,則預設採用欄位名進行查詢,當找不到與名稱匹配的bean時才按byType進行裝配。但是需要注意的是,如果name屬性一旦指定,就只會按照名稱進行裝配。

小結:@Autowired是按照先按 byType 後按 byName 進行匹配,@Resources是按照先按 byName 後按 byType進行匹配。

5、@Named/@Inject(瞭解)

這兩個註解的是JSR-330的一部分,而Spring 是支援JSR-330的。這些註解在使用上和Spring的註解一樣,只是想要匯入額外的相關jar包。如下:

        <!-- https://mvnrepository.com/artifact/javax.inject/javax.inject -->
        <dependency>
            <groupId>javax.inject</groupId>
            <artifactId>javax.inject</artifactId>
            <version>1</version>
        </dependency>

  • @Named 用來替代@Component 宣告一個Bean
  • @Inject 用來替代@Autowired來執行注入

實際上我們很少會使用這樣的註解,使用知道有這個東西即可。


參考連結: