聊聊依賴注入註解@Resource和@Autowired 原 薦
1. 前言
@Resource
和 @Autowired
註解都可以在 Spring Framework 應用中進行聲明式的依賴注入。而且面試中經常涉及到這兩個註解的知識點。今天我們來總結一下它們。
2.@Resource
全稱 javax.annotation.Resource
,它屬於 JSR-250 規範的一個註解,包含 Jakarta EE ( J2EE )中。 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
)以避免這種情況,設置 @Autowired
爲 false
。
/** * The type Autowired test. * * @author felord.cn * @since 9 :26 */ @Component public class AutowiredTest { // 一旦找不到 movieFinder 不會異常 而初始化爲 null @Autowired(required = false) private MovieFinder movieFinder; // ... }
這裏也有騷操作,你可以忽略 required
屬性。通過 Java 8 的 java.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獲取更多資訊