1. 前言

@Resource@Autowired 註解都可以在 Spring Framework 應用中進行聲明式的依賴注入。而且面試中經常涉及到這兩個註解的知識點。今天我們來總結一下它們。

2.@Resource

全稱 javax.annotation.Resource ,它屬於 JSR-250 規範的一個註解,包含 Jakarta EEJ2EE )中。 Spring 提供了對該註解的支持。我們來詳細瞭解一下該註解的規則。

該註解使用在成員屬性和setter方法上。默認情況下 @Resource 按照名稱注入,如果沒有顯式聲明名稱則按照變量名稱或者方法中對應的參數名稱進行注入。

如果我們希望在目標Bean中體現多態我們可以這樣寫:

/**
 * 多態的體現.
 *
 * @author felord.cn
 * @since 9 :26
 */
@Component
public class ResourceTest {
    @Resource
    private ApplicationRunner applicationRunner;    
    @Resource
    private ApplicationRunner runner;
    // ...
}

Qualifier 約束參見 Spring 註解 @Qualifier 詳細解析

3. @Autowired

@Autowired 通常適用於構造函數,成員變量以及方法上。它的機制是這樣的:

這個註解我們是需要好好聊聊的,日常使用頻率相當高。

3.1 標註在構造上

通過在目標 Bean 的構造函數上標註就可以注入對應的 Bean

package cn.felord;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.ApplicationRunner;
import org.springframework.stereotype.Component;

/**
 * @author felord.cn
 * @since 9:26
 **/
@Component
public class AutowiredTest {
 private final ApplicationRunner applicationRunner;

    @Autowired
    public AutowiredTest(ApplicationRunner applicationRunner) {
        this.applicationRunner = applicationRunner;
    }
}

Spring Framework 4.3 開始, @Autowired 如果目標Bean只定義一個構造函數,則不再需要在該構造函數上添加 @Autowired 註解。如果目標Bean有幾個構造函數可用,並且沒有主/默認構造函數,則必須至少有一個構造函數被 @Autowired 標記,以指示Spring IoC容器使用哪個構造函數。

3.2 標註在成員變量上

@Resource 一樣, @Autowired 也可以標註到目標 Bean 的成員變量上。

/**
 * @author felord.cn
 * @since 9:26
 **/
@Component
public class AutowiredTest {
    @Autowired
    private ApplicationRunner applicationRunner;
    
    // ...
    
}

3.3 標註到方法上

一般setter方法上使用的比較多。而且一個 @Autowired 支持注入多個參數。

/**
 * The type Autowired test.
 *
 * @author felord.cn
 * @since 9 :26
 */
@Component
public class AutowiredTest {

    private ApplicationRunner applicationRunner;
    private EmployeeMapper employeeMapper;
    private DepartmentMapper departmentMapper;

    /**
     * Sets application runner.
     *
     * @param applicationRunner the application runner
     */
    @Autowired
    public void setApplicationRunner(ApplicationRunner applicationRunner) {
        this.applicationRunner = applicationRunner;
    }


    /**
     * 支持多參數
     *
     * @param employeeMapper   the employee mapper
     * @param departmentMapper the department mapper
     */
    @Autowired
    public void prepare(EmployeeMapper employeeMapper, DepartmentMapper departmentMapper) {
        this.employeeMapper = employeeMapper;
        this.departmentMapper = departmentMapper;
    }

}

你以爲這就完了?下面這種方式估計大多數人並沒有在意過。

/**
 * The type Autowired test.
 *
 * @author felord.cn
 * @since 9 :26
 */
@Component
public class AutowiredTest {
    // 注入 數組
    @Autowired
    private MovieCatalog[] movieCatalogs;
    
    private Map<String, Movie> movies;
    
    private Set<CustomerPreferenceDao> customerPreferenceDaos;
    
    // 注入 set
    @Autowired
    public MovieRecommender(Set<CustomerPreferenceDao> customerPreferenceDaos) {
        this.customerPreferenceDaos = customerPreferenceDaos;
    }
            
    // 注入 map 
    @Autowired
    public void setMovieCatalogs(Map<String, Movie> movies) {
        this.movies = movies;
    }
   
    // ...
}

可以把Bean注入目標Bean的數組、集合容器中去。默認情況下,當給定注入點沒有匹配的候選Bean可用時,自動裝配將失敗。至少應有一個匹配元素。

如果您希望元素按照特定順序排序,則元素Bean可以實現 org.springframework.core.Ordered 接口或者對應註解 @Order 或標準 @Priority 。基於某些機制不建議使用註解方式來排序,否則無法達到預期期望,推薦使用接口 Ordered

3.4 裝配可選

@Resource 沒有提供可選擇裝配的特性,一旦無法裝配則會拋出異常;而 @Autowired 提供了 required 屬性(默認值爲 true )以避免這種情況,設置 @Autowiredfalse

/**
 * The type Autowired test.
 *
 * @author felord.cn
 * @since 9 :26
 */
@Component
public class AutowiredTest {
    // 一旦找不到 movieFinder  不會異常  而初始化爲 null
    @Autowired(required = false)
    private MovieFinder movieFinder;
    // ...
}

這裏也有騷操作,你可以忽略 required 屬性。通過 Java 8java.util.Optional 來表明候選Bean可選。

/**
 * The type Autowired test.
 *
 * @author felord.cn
 * @since 9 :26
 */
@Component
public class AutowiredTest {
public class SimpleMovieLister {
    // 使用 Optional 表明候選Bean可選
    @Autowired
    public void setMovieFinder(Optional<MovieFinder> movieFinder) {
     //   ...
    }
}

Spring 5.0 開始,您還可以使用 @Nullable 註解,這個註解可以你自己實現檢測邏輯或者直接使用 JSR-305 提供的 javax.annotation.Nullable

/**
 * The type Autowired test.
 *
 * @author felord.cn
 * @since 9 :26
 */
@Component
public class AutowiredTest {
public class SimpleMovieLister {
    // 使用 @Nullable 註解表明候選Bean可選
    @Autowired
    public void setMovieFinder(@Nullable MovieFinder movieFinder) {
      //  ...
    }
}

4.@Inject

Spring 3.0 開始, Spring 提供對 JSR-330 標準註解(依賴注入)的支持。 你需要引入依賴:

<dependency>
    <groupId>javax.inject</groupId>
    <artifactId>javax.inject</artifactId>
    <version>1</version>
</dependency>

然後你就可以使用相關的註解來進行依賴注入了,其中主要註解爲 @javax.inject.Inject 。大部分情況下該註解都可以代替 @Autowired 使用,但 @Inject 沒有 required 屬性,不過它也可以與 java.util.Optional 或使用 @Nullable 來達到同樣的效果。

大部分情況下沒有人喜歡額外引入 Jakarta EE 依賴來使用一個已經擁有的功能, Spring 堵死了 Jakarta EE 依賴注入的生態。

5. 總結

@Resource@Autowired 的優先級順序不同(參見上圖),另外 @Resource 屬於 Jakarta EE 規範而 @Autowired 屬於 Spring 範疇, @Resource 無法使用在構造參數中, @Autowired 支持 required 屬性。從面向對象來說, @Resource 更加適用於多態性的細粒度注入,而 @Autowired 更多專注於多態的單例注入。 @Inject 則沒必要過多討論,只作爲一個添頭。好了今天就到這裏,多多關注: 碼農小胖哥 ,更多幹貨知識分享。

關注公衆號:Felordcn獲取更多資訊

個人博客:https://felord.cn

相關文章