@TOCjava
本文簡述這三個Spring應用裏經常使用的註解區別。spring
官方文檔裏對@Resources的說明:app
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...框架
裏面有不少PDF能夠下載:測試
打開一看,其實就是Java支持的註解的文檔。這些文檔是最權威的:spa
文檔裏介紹,@Resources對Bean的注入按照以下的優先級進行:3d
咱們來看看Match by name的例子。下面的代碼試圖經過Match by Name注入一個名稱爲namedFile的Bean:code
@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的定義在以下代碼裏:blog
@Configuration public 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測試經過。rem
將使用bean的消費者代碼裏@Resource註解的name屬性去掉,使其變成下面這樣:
@Resource private File defaultFile;
測試仍然經過,是由於Match by Name的探測機制執行失敗後,進行下一輪Match by Type的探測,這一輪成功了。
定義兩個Bean:
@Configuration public 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;
這個註解定義在JSR-330裏,文檔連接:
https://jcp.org/en/jsr/detail...
注入的優先級:
注意@Inject注入的最高優先級方式爲Match by Type,而非@Resource的Match by Name.
任意定義一個待注入的Component:
@Component public 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()); } }
定義一個新的待注入組件:
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;
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代碼:
@Configuration public class ApplicationContextTestInjectName { @Bean public ArbitraryDependency yetAnotherFieldInjectDependency() { ArbitraryDependency yetAnotherFieldInjectDependency = new YetAnotherArbitraryDependency(); return yetAnotherFieldInjectDependency; } }
測試經過
這個註解和@Inject的用法一致,惟一區別就是@Autowired 屬於Spring框架提供的註解。例子略。
要獲取更多Jerry的原創文章,請關注公衆號"汪子熙":