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


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

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

  • @Autowired:它默認是按byType進行匹配,可以用於修飾類成員變量(字段)、Setter 方法、構造函數,甚至普通方法,但是前提是方法必須有至少一個參數。

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

①、作用於類的成員變量(字段 | Field)

注意:在IDEA編輯器中使用@Autowired作用於字段 (Field) 的時,IDEA會給出一個提示:Field injection is not recommended(意思是不再推薦使用字段注入),但是習慣了作用於字段,所以不必管它,如果你感覺不爽的話可以按照如下操作隱藏這個提示:

setting-->Editor-->inspections-->Spring-->Spring Core-->Code-->Filed injection warning去掉右邊的小勾勾,Apply-->OK即可。

具體為啥不推薦可以參考:https://zhuanlan.zhihu.com/p/92395282

然后創建的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方法省略......
}

測試代碼如下:

/**
 * 測試代碼
 */
@ComponentScan(value = "com.thr.pojo")
public class SpringTest1 {
    public static void main(String[] args) {
        //1.初始化Spring容器,通過注解加載
        ApplicationContext applicationContext = new AnnotationConfigApplicationContext(SpringTest1.class);
        //2.通過容器獲取實例
        User user =  applicationContext.getBean("user",User.class);
        //3.調用實例中的屬性
        System.out.println(user.getUserId()+"----"+
                user.getUserName()+"----"+
                user.getUserAge()+"----"+
                user.getGirlFriend());
    }
}

運行測試代碼,查看控制台打印的結果:

image

 

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

  (1) 作用於Setter方法:

image

  (2) 作用於構造函數:

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

image


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

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

image

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

image

通過運行的結果可以發現注入失敗了,但是不會報錯,只是返回為null。

image

補充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來執行注入

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


免責聲明!

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



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