@Resource与@Autowired的区别

440

我应该在依赖注入中使用哪个注释:@Resource (jsr250) 或 @Autowired(Spring 特定)?

过去我都成功地使用过这两个注释:@Resource(name="blah")@Autowired @Qualifier("blah")

我的直觉是坚持使用 @Resource 标签,因为它已经被 JSR 组织认可。
有人对此有强烈的看法吗?


FYI - 我已经删除了“更新”,这应该作为一个单独的问题提出。根据这个被拒绝的评论,“这个编辑偏离了帖子的原意。即使必须进行重大更改的编辑,也应该努力保留帖子所有者的目标”。 - mlo55
11个回答

581

@Autowired(或@Inject)和@Resource都可以很好地工作,但是它们有概念上的差异或意义上的差异。

  • @Resource表示按名称获取我已知的资源。名称从注释设置器或字段的名称中提取,或者从名称参数中提取。
  • @Inject@Autowired则尝试通过类型将适当的其他组件连接起来。

这是两个完全不同的概念。不幸的是,@Resource的Spring实现具有内置的后备机制,当按名称解析失败时会触发该机制。在这种情况下,它会退回到@Autowired类型的解析。虽然这个后备机制很方便,但它会导致很多混淆,因为人们不知道概念上的差异,并倾向于使用@Resource进行基于类型的自动装配。


89
是的,这应该是一个被接受的答案。例如,如果你有一个带有@Resource注解的字段,并且字段名称与容器中的bean的ID匹配,那么如果它们的类型不同,Spring将抛出 org.springframework.beans.factory.BeanNotOfRequiredTypeException - 这是因为在@Resource注解中首先按名称匹配bean,而不是按类型。但是,如果属性的名称不匹配bean的名称,那么Spring将按类型进行自动装配。 - Boris Treukhov
6
+1 是为了实际回答问题,而不是像被接受的答案那样只是推荐完全不同的“最佳实践”。我还发现这篇博客文章对于所有三种注释风格在几个常见场景下的结果都很有帮助:http://blogs.sourceallies.com/2011/08/spring-injection-with-resource-and-autowired/。 - Jules
1
请读者在此处找到@Jules指向的文章摘要:https://dev59.com/RG855IYBdhLWcg3w5Ikb#23887596 - Stephan
3
这句话的含义是:如果你想要注入一个 Map/List 类型的 Bean,@Autowired 注解将不能够工作。这种情况下,你将需要使用 @Resource 注解来实现。 - Ricardo van den Broek
如果 @autowire 标注在 setter 方法上,它将会按类型进行自动装配;如果标注在引用上,则会按名称进行自动装配。 - jayendra bhatt
显示剩余2条评论

213

在Spring 3.0之前的版本中,无论哪种方式都可以。

在Spring 3.0中,支持标准(JSR-330)注解@javax.inject.Inject。可以使用它与@Qualifier结合使用。需要注意的是,现在Spring也支持@javax.inject.Qualifier元注解:

@Qualifier
@Retention(RUNTIME)
public @interface YourQualifier {}

因此你可以拥有

<bean class="com.pkg.SomeBean">
   <qualifier type="YourQualifier"/>
</bean>
或者
@YourQualifier
@Component
public class SomeBean implements Foo { .. }

然后:

@Inject @YourQualifier private Foo foo;

这种方法更少使用字符串名称,这样可以避免拼写错误并且更易于维护。


至于原始问题:两者都未指定注释属性时,都通过类型进行注入。区别在于:

  • @Resource 允许您指定被注入的bean的名称
  • @Autowired 允许您将其标记为非强制性。

这可能看起来像一个愚蠢的问题,但是当你使用这种注入方式时,你需要为 foo 创建一个公共 setter 方法或者在 SomeBean 中创建一个带有 Foo 参数的构造函数吗? - Snekse
@Snekse - 我找到了答案:https://dev59.com/MXA65IYBdhLWcg3w-jym - Snekse
不需要。只需要这个字段即可。(Spring通过反射自动填充) - Bozho
2
@Bozho 这个答案实际上并没有展示 @Resource@Autowired 之间的区别,真正的答案是由 @Ichthyo 发布的那个,我认为这个答案需要更新。 - Boris Treukhov
1
是的。实际上,有时我会通过提供更好的方法来回答问题。但为了完整起见,我在下面包含了对原始问题的答案。 - Bozho
请注意,要使用@Inject,您需要额外的依赖项。 Maven工件和/或jar文件下载可以在此处找到:http://search.maven.org/#artifactdetails%7Cjavax.inject%7Cjavax.inject%7C1%7Cjar - Jules

87

主要区别在于,@Autowired 是一个 Spring 的注解,而 @Resource 则是由 JSR-250 指定的,正如你自己指出的那样。因此,后者是 Java 的一部分,而前者是 Spring 特有的。

因此,你在建议中提到,某种程度上是正确的。我发现人们使用 @Autowired@Qualifier,因为它更加强大。从一个框架到另一个框架的转移被认为是非常不可能的,如果不是神话的话,尤其是在 Spring 的情况下。


9
+1,因为使用@Autowired@Qualifier注解比JSR标准的@Resource注解更加强大(例如,使用@Autowired(required=false)时可以处理可选依赖项。而使用@Resource无法实现此功能)。 - Stefan Haberl

76

我想强调一下对于这个问题的回答@Jules提出的有用链接:@Resource, @Autowired和@ Inject的Spring注入。 我鼓励您完整阅读它,但是这里是其有用性的快速摘要:

如何使用注解选择正确的实现?

@Autowired@Inject

  1. 通过类型匹配
  2. 通过限定符进行约束
  3. 通过名称匹配

@Resource

  1. 通过名称匹配
  2. 通过类型匹配
  3. 通过限定符进行约束(如果已按名称找到匹配项,则忽略)

应该使用哪些注解(或哪些组合)来注入我的bean?

  1. 显式命名您的组件 [@Component("beanName")]

  2. 使用带有name属性的@Resource [@Resource(name="beanName")]

为什么不应该使用@Qualifier

除非您要创建一组类似的bean列表,否则避免使用@Qualifier注释。例如,您可能希望使用特定的@Qualifier注释标记一组规则。这种方法使将一组规则类注入到可用于处理数据的列表中变得简单。

我的程序是否因为bean注入而变慢?

为特定的包扫描组件[context:component-scan base-package="com.sourceallies.person"]。虽然这会导致更多的component-scan配置,但它减少了您向Spring上下文添加不必要组件的可能性。


参考资料: @Resource、@Autowired 和 @Inject 中的 Spring 注入


40

这是我从Spring 3.0.x参考手册中得到的内容:

提示

如果您想通过名称表示注释驱动的注入,请不要主要使用@Autowired,即使它在技术上可以通过@Qualifier值引用bean名称。相反,使用JSR-250 @Resource注释,其在语义上定义为通过其唯一名称标识特定目标组件,声明类型对匹配过程无关。

作为此语义差异的具体后果,本身定义为集合或映射类型的bean不能通过@Autowired进行注入,因为类型匹配不适用于它们。对于这样的bean,请使用@Resource,通过唯一名称引用特定的集合或映射bean。

@Autowired适用于字段、构造函数和多参数方法,允许通过参数级别的限定符注释进行缩小范围。相比之下,@Resource仅支持具有单个参数的字段和bean属性设置器方法。因此,如果您的注入目标是构造函数或多参数方法,请坚持使用限定符。


1
对于当前版本,请参阅https://docs.spring.io/spring/docs/current/spring-framework-reference/core.html#beans-autowired-annotation-qualifiers(提示已更新)。 - Ilya Serbis

30

@Autowired + @Qualifier 只能在 Spring DI 中使用,如果将来您想使用其他 DI,则 @Resource 是一个很好的选择。

我发现另一个非常重要的区别是,@Qualifier 不支持动态 bean 连接,因为 @Qualifier 不支持占位符,而 @Resource 很擅长这方面。

例如:如果您有一个具有多个实现的接口,像这样:

interface parent {

}
@Service("actualService")
class ActualService implements parent{

}
@Service("stubbedService")
class SubbedService implements parent{

}

使用 @Autowired 和 @Qualifier,您需要设置特定的子实现, 例如

@Autowired
@Qualifier("actualService") or 
@Qualifier("stubbedService") 
Parent object;

使用@Resource可以提供占位符并使用属性文件注入特定的子实现,而不提供占位符。

@Resource(name="${service.name}")
Parent object;  

服务名在属性文件中设置为

#service.name=actualService
 service.name=stubbedService

希望能对某人有所帮助 :)


19

两者都很好。使用Resource的优点在于,将来如果您想要使用除Spring之外的另一个DI框架,您的代码更改会更简单。而使用Autowired会使您的代码与Spring的DI紧密耦合。


22
不可能发生。即使真的发生了,对注释名称进行查找/替换只会是你面临的最小问题。 - Daniel Alexiuc

18

当您从这两个注释的基类进行严格分析时,您将意识到以下差异。

@Autowired使用AutowiredAnnotationBeanPostProcessor注入依赖项。
@Resource使用CommonAnnotationBeanPostProcessor注入依赖项。

尽管它们使用不同的后处理器类,但它们的行为几乎相同。 关键差异在于它们的执行路径,我已经在下面突出显示了它们。

@Autowired / @Inject

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

@Resource

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


6

使用@Resource,您可以进行bean自我注入,这可能是必要的,以便运行由bean后处理器添加的所有额外逻辑,如事务或安全相关内容。

在Spring 4.3+中,@Autowired也能够实现这一点。


2

@Resource经常被高级对象使用,这些对象是通过JNDI定义的。 @Autowired@Inject将被更常见的bean使用。

据我所知,这不是一个规范,甚至不是一个约定。这更像是标准代码使用这些注解的逻辑方式。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接