使用@RESOURCE、@AUTOWIRED 和 @INJECT 进行 SPRING 注入

概述

我曾多次被要求解释使用“@Resource”、“@Autowired”和“@Inject”注入 Spring bean 之间的区别。虽然我从他人那里得到了一些指导,并阅读了一些关于这个主题的帖子,但并没有形成完整的概念。

注释

注解package来源
@Resourcejavax.annotationjava
@Injectjavax.injectjava
@Qualifierjavax.injectjava
@Qualifierorg.springframework.bean.factoryspring


为了探索每个注解的行为,我在spring项目代码中调试和使用这些注解。我在研究中使用了 Spring 3.0.5.RELEASE。以下是我的发现总结。

代码

我想知道“@Resource”、“@Autowired”和“@Inject”是如何解决依赖关系的。我创建了一个名为“Party”的接口并创建了两个实现类。这允许我在不使用具体类型的情况下注入 bean,在多种类型匹配时确定 Spring 如何解析 bean。

public interface Party {

}

'Person' 是一个Component,它实现了 'Party'。

package com.myTest.person;
...
@Component
public class Person implements Party {

}

Organization”是一个Component,它实现了“Party”。

package com.myTest.organization;
...
@Component
public class Organization implements Party {

}

我设置了一个 Spring 上下文配置来扫描这两个包中标有“@Component”的 bean。

<context:component-scan base-package="com.myTest.organization"/>
<context:component-scan base-package="com.myTest.person"/>

测试

测试 1:二义性的 Bean, 在这个测试中,我注入了一个在 Spring 上下文中有多个实现的“Party”bean。

@Resource
private Party party;
@Autowired
private Party party;
@Inject
private Party party;

在这三种情况下,都会抛出“NoSuchBeanDefinitionException”。虽然此异常的名称暗示未找到 bean,但该消息说明找到了两个 bean。所有这些注释都会导致相同的异常。

org.springframework.beans.factory.NoSuchBeanDefinitionException:
No unique bean of type [com.sourceallies.Party] is defined:
expected single matching bean but found 2: [organization, person]

测试 2:字段名称 在此测试中,我将 Party 字段名称命名为 person。默认情况下,标记为“@Component”的 bean 将与类具有相同的名称。因此,“Person”类的名称是person。

@Resource
private Party person;
@Autowired
private Party person;
@Inject
private Party person;

'@Resource' 还可以采用可选的 'name' 属性。这相当于上面的“@Resource”代码。在这种情况下,字段变量名称仍然是“party”。'@Autowired' 或 '@Inject' 没有等效的语法,如果想指实现类似的指定,您必须使用“@Qualifier”。稍后将介绍此语法。

@Resource(name="person")
private Party party;

所有这些注释都成功的注入了“Person”类的bean。

测试 3:字段类型 在此测试中,我将类型更改为“Person”。

@Resource
private Person party;

@Autowired
private Person party;
@Inject
private Person party;

所有这些注释都成功的注入了“Person”类的bean。

测试 4:默认名称限定符 在此测试中,我使用“@Qualifier”注释来指向“Person”组件的默认名称。

@Resource
@Qualifier("person")
private Party party;
@Autowired
@Qualifier("person")
private Party party;
@Inject
@Qualifier("person")
private Party party;

所有这些注释都成功的注入了“Person”类的bean。

测试 5:限定名称 我在 'Person' 类中添加了一个 '@Qualifier' 注释

package com.springTest.person;
...
@Component
@Qualifier("personBean")
public class Person implements Party {

}

在此测试中,我使用“@Qualifier”注释来指向“Person”组件的限定名称。

@Resource
@Qualifier("personBean")
private Party party;
@Autowired
@Qualifier("personBean")
private Party party;
@Inject
@Qualifier("personBean")
private Party party;

所有这些注释都成功的注入了“Person”类的bean。

测试 6:Bean 列表 在这个测试中,我注入了一个 bean 列表。

所有这些注释都将 2 个 bean 注入列表。这也可以通过“@Qualifier”来完成。每个标记有特定限定符的 bean 将被添加到列表中。

测试 7:冲突 在这个测试中,我添加了一个错误的“@Qualifier”和一个匹配的字段名称。

@Resource
@Qualifier("bad")
private Party person;
@Autowired
@Qualifier("bad")
private Party person;
@Inject
@Qualifier("bad")
private Party person;

在这种情况下,标有“@Resource”的字段使用字段名称匹配并忽略“@Qualifier”。'Person'类的bean成功被注入。

但是,“@Autowired”和“@Inject”字段会引发“NoSuchBeanDefinitionException”错误,因为它找不到与“@Qualifier”匹配的 bean。

 org.springframework.beans.factory.NoSuchBeanDefinitionException:
No matching bean of type [com.sourceallies.Party] found for dependency:
expected at least 1 bean which qualifies as autowire candidate for this dependency.
Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true),
@org.springframework.beans.factory.annotation.Qualifier(value=bad)}

结论

除了测试 2 和 7 之外,配置和结果是相同的。当我深入了解时,我确定 '@Autowired' 和 '@Inject' 注释的行为相同。这两个注释都使用“AutowiredAnnotationBeanPostProcessor”来注入依赖项。'@Autowired' 和 '@Inject' 可以互换使用以注入 Spring bean。

但是,“@Resource”注释使用“CommonAnnotationBeanPostProcessor”来注入依赖项。即使它们使用不同的后处理器类,它们的行为也几乎相同。下面是它们的执行的先后次序:

@Autowired 和 @Inject

  1. 按类型匹配
  2. 限定词的限制
  3. 按名称匹配

@Resource

  1. 按名称匹配
  2. 按类型匹配
  3. 限定符限制(如果按名称找到匹配,则忽略)

虽然可以说@Resource在名称上比@Autowired和@Inject执行得更快,但它可以忽略不计。这不是支持@Resource的充分理由。然而,我更喜欢 @Resource注释,因为它简洁的符号风格。

@Resource(name="person")
@Autowired
@Qualifier("person")

@Inject
@Qualifier("person")

您可能会争辩说,如果您使用字段名称来标识 bean 名称,它们可以同样简洁。

@Resource
private Party person;
@Autowired
private Party person;
@Inject
private Party person;

确实如此,但是如果您想重构代码怎么办?通过简单地修改name属性,您不再指代同一个 bean。

在使用注解连接bean 时,我推荐以下做法。

Spring 注解风格最佳实践

  1. 显式命名您的组件 [@Component("beanName")]
  2. 将 '@Resource' 与 'name' 属性一起使用 [@Resource(name="beanName")]
  3. 除非您想创建 bean 的列表,否则避免使用“@Qualifier”注释。例如,您可能希望使用特定的“@Qualifier”注释标记一组规则。这种方法可以将一组规则类注入到处理数据的列表中。
  4. 扫描组件的特定包 [context:component-scan base-package="com.sourceallies.person"]。虽然这将导致更多的组件扫描配置,但它可以避免将不必要的Component添加到Spring 上下文。

遵循这些指南将提高 Spring 注释配置的可读性和稳定性。

参考资料:

https://www.sourceallies.com/2011/08/spring-injection-with-resource-and-autowired/

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值