一文让您搞清楚@Resources, @Inject和@Autowired的区别

本文简述这三个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

里面有很多PDF可以下载:

打开一看,其实就是Java支持的注解的文档。这些文档是最权威的:

文档里介绍,@Resources对Bean的注入按照如下的优先级进行:

  1. Match by Name
  2. Match by Type
  3. 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;
    }
}

测试代码:

@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

注入的优先级:

  1. Match by Type
  2. Match by Qualifier
  3. 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框架提供的注解。例子略。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值