溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點(diǎn)擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

Spring和IDEA為什么都不推薦使用@Autowired注解

發(fā)布時(shí)間:2022-04-02 15:49:26 來源:億速云 閱讀:523 作者:iii 欄目:開發(fā)技術(shù)

今天小編給大家分享一下Spring和IDEA為什么都不推薦使用@Autowired注解的相關(guān)知識(shí)點(diǎn),內(nèi)容詳細(xì),邏輯清晰,相信大部分人都還太了解這方面的知識(shí),所以分享這篇文章給大家參考一下,希望大家閱讀完這篇文章后有所收獲,下面我們一起來了解一下吧。

    Spring為什么不推薦使用@Autowired 注解

    背景

    做開發(fā)的同學(xué)可能都會(huì)發(fā)現(xiàn), idea 在我們經(jīng)常使用的@Autowired 注解上添加了警告
    警告內(nèi)容是: Field injection is not recommended, 譯為: 不推薦使用屬性注入

    Spring和IDEA為什么都不推薦使用@Autowired注解

    我們點(diǎn)擊右側(cè)三個(gè)小點(diǎn)查看描述, 可以看到信息如下圖

    Spring和IDEA為什么都不推薦使用@Autowired注解

    原因詳情描述: Inspection info: Spring Team recommends: "Always use constructor based dependency injection in your beans. Always use assertions for mandatory dependencies".
    譯為: Spring 團(tuán)隊(duì)建議: 始終在您的 bean 中使用基于構(gòu)造函數(shù)的依賴注入。始終對強(qiáng)制依賴項(xiàng)使用斷言

    Spring和IDEA為什么都不推薦使用@Autowired注解

    原因

    為什么 Spring 建議我們在Bean中使用構(gòu)造注入呢?
    想要回答這個(gè)問題, 我們需要了解 Spring的依賴注入(DI)方式
    Spring常用的注入方式有: 簡單類型注入, 集合類型注入, 域?qū)傩宰詣?dòng)注入, 自動(dòng)注入的類別, 空值注入, 構(gòu)造注入
    可以簡化為: 屬性注入, 構(gòu)造方法注入, set 方法注入

    下面, 來用代碼展示下三種方式注入

    屬性注入
    可以看到, 我們開發(fā)最常用的就是屬性注入

    @RestController
    public class AppointmentNumberConfigurationController {
    
        @Autowired
        private AppointmentNumberConfigurationService numberConfigurationService;
    }

    set 方法注入
    set 方法注入也會(huì)用到@Autowired注解,但使用方式與屬性注入有所不同,
    屬性注入是用在成員變量上,而set 方法的時(shí)候,是用在成員變量的Setter函數(shù)上。

    @RestController
    public class AppointmentNumberConfigurationController {
    
    
        private AppointmentNumberConfigurationService numberConfigurationService;
    
        @Autowired
        public void setNumberConfigurationService(AppointmentNumberConfigurationService numberConfigurationService) {
            this.numberConfigurationService = numberConfigurationService;
    }

    構(gòu)造方法注入
    Constructor Injection是構(gòu)造器注入,是我們最為推薦的一種使用方式。
    但是, 每次注入都按照這樣的流程去構(gòu)造注入的話, 會(huì)顯得比較麻煩.
    至于如何去簡化這一步驟, 我們可以繼續(xù)往下看.

    @RestController
    public class AppointmentNumberConfigurationController {
    
        final AppointmentNumberConfigurationService numberConfigurationService;
        
        public AppointmentNumberConfigurationController(AppointmentNumberConfigurationService numberConfigurationService) {
            this.numberConfigurationService = numberConfigurationService;
        }
        }

    三種方式對比如下

    Spring和IDEA為什么都不推薦使用@Autowired注解

    使用屬性注入可能會(huì)出現(xiàn)的問題

    基于屬性注入的方式, 違背單一職責(zé)原則
    因?yàn)楝F(xiàn)在的業(yè)務(wù)一般都會(huì)使用很多依賴, 但擁有太多的依賴通常意味著承擔(dān)更多的責(zé)任,而這顯然違背了單一職責(zé)原則.
    并且類和依賴容器強(qiáng)耦合,不能在容器外使用。
    基于屬性注入的方式, 容易導(dǎo)致Spring 初始化失敗
    因?yàn)楝F(xiàn)在在Spring特別是Spring Boot使用中, 經(jīng)常會(huì)因?yàn)槌跏蓟臅r(shí)候, 由于屬性在被注入前就引用而導(dǎo)致npe(空指針錯(cuò)誤),
    進(jìn)而導(dǎo)致容器初始化失敗(類似下面代碼塊). Java 在初始化一個(gè)類時(shí),
    是按照 靜態(tài)變量或靜態(tài)語句塊 –> 實(shí)例變量或初始化語句塊 –> 構(gòu)造方法 -> @Autowired 的順序。
    所以在執(zhí)行這個(gè)類的構(gòu)造方法時(shí),person 對象尚未被注入,它的值還是 null。
    通過@Autowired 注入, 又因?yàn)槭?ByType 注入, 因此有可能會(huì)出現(xiàn)兩個(gè)相同的類型bean
    如下代碼快, 就會(huì)產(chǎn)生兩個(gè)相同的Bean, 進(jìn)而導(dǎo)致Spring 裝配失敗
    //2. 基于屬性注入的方式, 容易導(dǎo)致Spring 初始化失敗
    @Autowired
    private Person person;
    
    private String company;
    
    public UserServiceImpl(){
        this.company = person.getCompany();
    }
    
    
    //3. 通過@Autowired 注入, 又因?yàn)槭?nbsp;ByType 注入, 因此有可能會(huì)出現(xiàn)兩個(gè)相同的類型bean
    public interface IUser {
        void say();
    }
    
    @Service
    public class User1 implements IUser{
        @Override
        public void say() {
        }
    }
    
    @Service
    public class User2 implements IUser{
        @Override
        public void say() {
        }
    }
    
    @Service
    public class UserService {
    
        @Autowired
        private IUser user;
    }

    解決

    如果一定要使用屬性注入, 可以使用 @Resource 代替 @Autowired 注解
    @Resource的作用相當(dāng)于@Autowired,只不過@Autowired按照byType自動(dòng)注入。
    如果我們想使用按照名稱byName來裝配,可以結(jié)合@Qualifier注解一起使用。

    如果可能的話, 盡量使用構(gòu)造注入
    Lombok提供了一個(gè)注解@RequiredArgsConstructor, 可以方便我們快速進(jìn)行構(gòu)造注入, 例如:

    @RestController
    @RequiredArgsConstructor
    public class AppointmentNumberConfigurationController {
        
        final AppointmentNumberConfigurationService numberConfigurationService;
        }

    同時(shí)需要注意:

    使用@RequiredArgsConstructor注解需要導(dǎo)入Lombok 包 或者安裝lombok 插件

      <dependency>
          <groupId>org.projectlombok</groupId>
          <artifactId>lombok</artifactId>
          <version>1.18.16</version>
      </dependency>

    必須聲明的變量為final

    根據(jù)構(gòu)造器注入的,相當(dāng)于當(dāng)容器調(diào)用帶有一組參數(shù)的類構(gòu)造函數(shù)時(shí),基于構(gòu)造函數(shù)的 DI 就完成了,
    其中每個(gè)參數(shù)代表一個(gè)對其他類的依賴?;跇?gòu)造方法為屬性賦值,容器通過調(diào)用類的構(gòu)造方法將其進(jìn)行依賴注入

    思考

    為什么推薦使用@Resource,不推薦使用@Autowired

    通過對問題1 的梳理, 我們可以知道.
    因?yàn)?code>@Autowired 注解在Bean 注入的時(shí)候是基于ByType, 因此會(huì)由于注入兩個(gè)相同類型的Bean導(dǎo)致裝配失敗

    @Resource的作用相當(dāng)于@Autowired,只不過@Autowired按照byType自動(dòng)注入。
    如果我們想使用按照名稱byName來裝配,可以結(jié)合@Qualifier注解一起使用。

    @Resource裝配順序:
    ①如果同時(shí)指定了name和type,則從Spring上下文中找到唯一匹配的bean進(jìn)行裝配,找不到則拋出異常。
    ②如果指定了name,則從上下文中查找名稱(id)匹配的bean進(jìn)行裝配,找不到則拋出異常。
    ③如果指定了type,則從上下文中找到類似匹配的唯一bean進(jìn)行裝配,找不到或是找到多個(gè),都會(huì)拋出異常。
    ④如果既沒有指定name,又沒有指定type,則自動(dòng)按照byName方式進(jìn)行裝配;如果沒有匹配,則回退為一個(gè)原始類型進(jìn)行匹配,如果匹配則自動(dòng)裝配。

    因此, 如果一定要使用屬性注入, 可以使用 @Resource 代替 @Autowired 注解

    @Autowired, @Qualifier, @Resource, 三者有何區(qū)別

    • @Autowired: 通過byType 方式進(jìn)行裝配, 找不到或是找到多個(gè),都會(huì)拋出異常。

    • @Qualifier: 如果想讓@Autowired 注入的Bean進(jìn)行 byName裝配, 可以使用 @Qualifier 進(jìn)行指定

    • @Resource :作用相當(dāng)于@Autowired,只不過 @Resource 默認(rèn)按照byName方式裝配, 如果沒有匹配, 則退回到 byType 方式進(jìn)行裝配

    以上就是“Spring和IDEA為什么都不推薦使用@Autowired注解”這篇文章的所有內(nèi)容,感謝各位的閱讀!相信大家閱讀完這篇文章都有很大的收獲,小編每天都會(huì)為大家更新不同的知識(shí),如果還想學(xué)習(xí)更多的知識(shí),請關(guān)注億速云行業(yè)資訊頻道。

    向AI問一下細(xì)節(jié)

    免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

    AI