Spring 注解 @Resources, @Inject和@Autowired 的区别辨析

网友投稿 729 2022-05-29

@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的定义在如下代码里:

@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测试通过。

Match by Type

将使用bean的消费者代码里@Resource注解的name属性去掉,使其变成下面这样:

@Resource private File defaultFile;

测试仍然通过,是因为Match by Name的探测机制执行失败后,进行下一轮Match by Type的探测,这一轮成功了。

Match by Qualifier

定义两个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; } }

测试代码:

Spring 注解 @Resources, @Inject和@Autowired 的区别辨析

@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:

@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()); } }

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代码:

@Configuration public class ApplicationContextTestInjectName { @Bean public ArbitraryDependency yetAnotherFieldInjectDependency() { ArbitraryDependency yetAnotherFieldInjectDependency = new YetAnotherArbitraryDependency(); return yetAnotherFieldInjectDependency; } }

测试通过

@Autowired

这个注解和@Inject的用法一致,唯一区别就是@Autowired 属于Spring框架提供的注解。例子略。

Java Spring

版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:定位之绝对定位
下一篇:《Office 2019高效办公三合一从入门到精通 : 视频自学版》 —3.4.2设置通栏标题
相关文章