前言
@Resource和@Autowired注解都可以在Spring Framework應用中進行聲明式的依賴注入。而且面試中經常涉及到這兩個注解的知識點。今天我們來總結一下它們。
1. @Resource
全稱javax.annotation.Resource,它屬於JSR-250規范的一個注解,包含Jakarta EE(J2EE)中。Spring提供了對該注解的支持。我們來詳細了解一下該注解的規則。
該注解使用在成員屬性和setter方法上。默認情況下@Resource按照名稱注入,如果沒有顯式聲明名稱則按照變量名稱或者方法中對應的參數名稱進行注入。
如果我們希望在目標Bean中體現多態我們可以這樣寫:
@Component
public class ResourceTest {
@Resource
private ApplicationRunner applicationRunner;
@Resource
private ApplicationRunner runner;
// ...
}
- Qualifier 約束參見 Spring 注解 @Qualifier 詳細解析
2. @Autowired
@Autowired通常適用於構造函數,成員變量以及方法上。它的機制是這樣的:
Autowired流程
這個注解我們是需要好好聊聊的,日常使用頻率相當高。
2.1 標注在構造上
通過在目標Bean的構造函數上標注就可以注入對應的Bean。
package cn.felord;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.ApplicationRunner;
import org.springframework.stereotype.Component;
@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容器使用哪個構造函數。
2.2 標注在成員變量上
和@Resource一樣,@Autowired也可以標注到目標Bean的成員變量上。
@Component
public class AutowiredTest {
@Autowired
private ApplicationRunner applicationRunner;
// ...
}
2.3 標注到方法上
一般setter方法上使用的比較多。而且一個 @Autowired 支持注入多個參數。
@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. */ @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。
2.4 裝配可選
@Resource沒有提供可選擇裝配的特性,一旦無法裝配則會拋出異常;而@Autowired提供了required屬性(默認值為true)以避免這種情況,設置@Autowired為false。
/**
* The type Autowired test.
*/
@Component
public class AutowiredTest {
// 一旦找不到 movieFinder 不會異常 而初始化為 null
@Autowired(required = false)
private MovieFinder movieFinder;
// ...
}
- 這里也有騷操作,你可以忽略required屬性。通過 Java 8的 java.util.Optional來表明候選Bean可選。
/**
* The type Autowired test
*/
@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.
*/
@Component
public class AutowiredTest {
public class SimpleMovieLister {
// 使用 @Nullable 注解表明候選Bean可選
@Autowired
public void setMovieFinder(@Nullable MovieFinder movieFinder) {
// ...
}
}
3. @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依賴注入的生態。
4.總結
@Resource和@Autowired的優先級順序不同(參見上圖),另外@Resource屬於 Jakarta EE規范而@Autowired屬於Spring范疇,@Resource無法使用在構造參數中,@Autowired支持required屬性。從面向對象來說,@Resource更加適用於多態性的細粒度注入,而@Autowired更多專注於多態的單例注入。@Inject 則沒必要過多討論,只作為一個添頭。