一文讓您搞清楚@Resources, @Inject和@Autowired的區別
@ TOC
本文簡述這三個Spring應用裡常用的註解區別。
@Resources
官方文件裡對@Resources的說明:
The @Resource annotation is part of the JSR-250 annotation collection and is packaged with Jakarta EE.
什麼是JSR-250呢?訪問這個連結: https:// jcp.org/en/jsr/detail? id=250
裡面有很多PDF可以下載:
開啟一看,其實就是Java支援的註解的文件。這些文件是最權威的:
文件裡介紹,@Resources對Bean的注入按照如下的優先順序進行:
- Match by Name
- Match by Type
- Match by Qualifier
Match by Name
我們來看看Match by name的例子。下面的程式碼試圖透過Match by Name注入一個名稱為namedFile的Bean:
@RunWith(SpringJUnit4ClassRunner.class)@ContextConfiguration(
loader=AnnotationConfigContextLoader.class,
classes=ApplicationContextTestResourceNameType.class)public class FieldResourceInjectionIntegrationTest {
@Resource(name="namedFile")
private File defaultFile;
@Test
public void givenResourceAnnotation_WhenOnField_ThenDependencyValid(){
assertNotNull(defaultFile);
assertEquals("namedFile.txt", defaultFile.getName());
}}
Bean的定義在如下程式碼裡:
@Configurationpublic class ApplicationContextTestResourceNameType {
@Bean(name="namedFile")
public File namedFile() {
File namedFile = new File("namedFile.txt");
return namedFile;
}}
執行時,申明Bean依賴處的@Resource的Name屬性和Bean定義處@Bean的Name屬性值一致,Match by Name測試透過。
Match by Type
將使用bean的消費者程式碼裡@Resource註解的name屬性去掉,使其變成下面這樣:
@Resourceprivate File defaultFile;
測試仍然透過,是因為Match by Name的探測機制執行失敗後,進行下一輪Match by Type的探測,這一輪成功了。
Match by Qualifier
定義兩個Bean:
@Configurationpublic class ApplicationContextTestResourceQualifier {
@Bean(name="defaultFile")
public File defaultFile() {
File defaultFile = new File("defaultFile.txt");
return defaultFile;
}
@Bean(name="namedFile")
public File namedFile() {
File namedFile = new File("namedFile.txt");
return namedFile;
}}
測試程式碼:
@RunWith(SpringJUnit4ClassRunner.class)@ContextConfiguration(
loader=AnnotationConfigContextLoader.class,
classes=ApplicationContextTestResourceQualifier.class)public class QualifierResourceInjectionIntegrationTest {
@Resource
private File dependency1;
@Resource
private File dependency2;
@Test
public void givenResourceAnnotation_WhenField_ThenDependency1Valid(){
assertNotNull(dependency1);
assertEquals("defaultFile.txt", dependency1.getName());
}
@Test
public void givenResourceQualifier_WhenField_ThenDependency2Valid(){
assertNotNull(dependency2);
assertEquals("namedFile.txt", dependency2.getName());
}}
這一次執行失敗,遇到異常org.springframework.beans.factory.NoUniqueBeanDefinitionException.
原因是因為我們的測試程式碼裡,沒有指定注入Bean的名稱,因此Spring的Match by Name探測失敗,進行Match by Type時,探測到兩個型別一樣的Bean,Spring框架不知道注入哪一個,所以就報異常了。
避免這個異常也很容易,使用@Qualifier.程式碼如下:
@Resource@Qualifier("defaultFile")private File dependency1;@Resource@Qualifier("namedFile")private File dependency2;
@Inject
這個註解定義在JSR-330裡,文件連結:
https:// jcp.org/en/jsr/detail? id=330
注入的優先順序:
- Match by Type
- Match by Qualifier
- Match by Name
Match by Type
注意@Inject注入的最高優先順序方式為Match by Type,而非@Resource的Match by Name.
任意定義一個待注入的Component:
@Componentpublic class ArbitraryDependency {
private final String label = "Arbitrary Dependency";
public String toString() {
return label;
}}
使用@Inject注入:
@RunWith(SpringJUnit4ClassRunner.class)@ContextConfiguration(
loader=AnnotationConfigContextLoader.class,
classes=ApplicationContextTestInjectType.class)public class FieldInjectIntegrationTest {
@Inject
private ArbitraryDependency fieldInjectDependency;
@Test
public void givenInjectAnnotation_WhenOnField_ThenValidDependency(){
assertNotNull(fieldInjectDependency);
assertEquals("Arbitrary Dependency",
fieldInjectDependency.toString());
}}
Match by Qualifier
定義一個新的待注入元件:
public class AnotherArbitraryDependency extends ArbitraryDependency {
private final String label = "Another Arbitrary Dependency";
public String toString() {
return label;
}}
測試程式碼:
@RunWith(SpringJUnit4ClassRunner.class)@ContextConfiguration(
loader=AnnotationConfigContextLoader.class,
classes=ApplicationContextTestInjectQualifier.class)public class FieldQualifierInjectIntegrationTest {
@Inject
private ArbitraryDependency defaultDependency;
@Inject
private ArbitraryDependency namedDependency;
@Test
public void givenInjectQualifier_WhenOnField_ThenDefaultFileValid(){
assertNotNull(defaultDependency);
assertEquals("Arbitrary Dependency",
defaultDependency.toString());
}
@Test
public void givenInjectQualifier_WhenOnField_ThenNamedFileValid(){
assertNotNull(defaultDependency);
assertEquals("Another Arbitrary Dependency",
namedDependency.toString());
}}
和之前@Resource的第一次試圖透過Match by Type注入一樣失敗,遇到異常:NoUniqueBeanDefinitionException
利用@Qualifier避免這個異常:
@Inject@Qualifier("defaultFile")private ArbitraryDependency defaultDependency;@Inject@Qualifier("namedFile")private ArbitraryDependency namedDependency;
Match by Name
public class YetAnotherArbitraryDependency extends ArbitraryDependency {
private final String label = "Yet Another Arbitrary Dependency";
public String toString() {
return label;
}}
消費者程式碼:
@RunWith(SpringJUnit4ClassRunner.class)@ContextConfiguration(
loader=AnnotationConfigContextLoader.class,
classes=ApplicationContextTestInjectName.class)public class FieldByNameInjectIntegrationTest {
@Inject
@Named("yetAnotherFieldInjectDependency")
private ArbitraryDependency yetAnotherFieldInjectDependency;
@Test
public void givenInjectQualifier_WhenSetOnField_ThenDependencyValid(){
assertNotNull(yetAnotherFieldInjectDependency);
assertEquals("Yet Another Arbitrary Dependency",
yetAnotherFieldInjectDependency.toString());
}}
application context程式碼:
@Configurationpublic class ApplicationContextTestInjectName {
@Bean
public ArbitraryDependency yetAnotherFieldInjectDependency() {
ArbitraryDependency yetAnotherFieldInjectDependency =
new YetAnotherArbitraryDependency();
return yetAnotherFieldInjectDependency;
}}
測試透過
@Autowired
這個註解和@Inject的用法一致,唯一區別就是@Autowired 屬於Spring框架提供的註解。例子略。
要獲取更多Jerry的原創文章,請關注公眾號"汪子熙":
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/24475491/viewspace-2688370/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- @Autowired和@Resource的區別
- @Resource和@Autowired的區別
- @Autowired 和 @ Resource的區別
- @Autowired和@Resource有哪些區別
- 【Java面試】@Resource 和 @Autowired 的區別Java面試
- @Autowired 與@Resource的區別
- @Resource,@Autowired,@Inject3種注入方式詳解
- spring下應用@Resource, @Autowired 和 @Inject註解進行依賴注入的差異Spring依賴注入
- 容器和容器映象的區別,您真的瞭解嗎
- 一文搞懂Session和Cookie的用法及區別SessionCookie
- 一文讀懂BeanFactory和FactoryBean區別Bean
- 【Java註解用法】@Autowired 與@Resource的區別以及@Qualifier的介紹Java
- 一文搞懂exports和module.exports的關係和區別Export
- 3分鐘搞清楚程式與執行緒的區別執行緒
- 徹底搞清楚ConcurrentHashMap的實現原理(含JDK1.7和JDK1.8的區別)HashMapJDK
- 一文帶你搞清楚Python的多執行緒和多程序Python執行緒
- 一文搞清楚 DNS 的來龍去脈DNS
- 一文看懂上交易所和上主網的區別
- 一文告訴你資料和資訊的區別
- 一文搞懂 $_POST 和 file_get_contents ("PHP://input") 的區別PHP
- ../和./和/的區別
- LinkedList和ArrayList的區別、Vector和ArrayList的區別
- http和https的區別/get和post的區別HTTP
- 一文徹底搞清楚 Material DesignMaterial Design
- ||和??的區別
- /*和/**的區別
- 一文搞懂TCP與UDP的區別TCPUDP
- 一文看懂RPA與Excel宏的區別Excel
- makefile =和:=的區別
- ++a和a++的區別
- ./ 和sh 的區別
- jquery $(this) 和this的區別jQuery
- JQuery this和$(this)的區別jQuery
- T和?的區別
- 高階JAVA碼農必須搞清楚它們的區別:instanceof、isInstance、isAssignableFromJava
- 一文了解 ng-template, ng-content, ng-container, 和 *ngTemplateOutlet的區別AI
- 一文看懂npm、yarn、pnpm之間的區別NPMYarn
- 一文搞清楚Java中的方法、常量、變數、引數Java變數