我应该在依赖注入中使用哪个注释:@Resource (jsr250) 或 @Autowired(Spring 特定)?
过去我都成功地使用过这两个注释:@Resource(name="blah")
和 @Autowired @Qualifier("blah")
我的直觉是坚持使用 @Resource
标签,因为它已经被 JSR 组织认可。
有人对此有强烈的看法吗?
我应该在依赖注入中使用哪个注释:@Resource (jsr250) 或 @Autowired(Spring 特定)?
过去我都成功地使用过这两个注释:@Resource(name="blah")
和 @Autowired @Qualifier("blah")
我的直觉是坚持使用 @Resource
标签,因为它已经被 JSR 组织认可。
有人对此有强烈的看法吗?
@Autowired
(或@Inject
)和@Resource
都可以很好地工作,但是它们有概念上的差异或意义上的差异。
@Resource
表示按名称获取我已知的资源。名称从注释设置器或字段的名称中提取,或者从名称参数中提取。@Inject
或@Autowired
则尝试通过类型将适当的其他组件连接起来。这是两个完全不同的概念。不幸的是,@Resource
的Spring实现具有内置的后备机制,当按名称解析失败时会触发该机制。在这种情况下,它会退回到@Autowired
类型的解析。虽然这个后备机制很方便,但它会导致很多混淆,因为人们不知道概念上的差异,并倾向于使用@Resource
进行基于类型的自动装配。
@Resource
注解的字段,并且字段名称与容器中的bean的ID匹配,那么如果它们的类型不同,Spring将抛出 org.springframework.beans.factory.BeanNotOfRequiredTypeException
- 这是因为在@Resource
注解中首先按名称匹配bean,而不是按类型。但是,如果属性的名称不匹配bean的名称,那么Spring将按类型进行自动装配。 - Boris Treukhov@Autowired
注解将不能够工作。这种情况下,你将需要使用 @Resource
注解来实现。 - Ricardo van den Broek在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@Resource
和 @Autowired
之间的区别,真正的答案是由 @Ichthyo 发布的那个,我认为这个答案需要更新。 - Boris Treukhov主要区别在于,@Autowired
是一个 Spring 的注解,而 @Resource
则是由 JSR-250 指定的,正如你自己指出的那样。因此,后者是 Java 的一部分,而前者是 Spring 特有的。
因此,你在建议中提到,某种程度上是正确的。我发现人们使用 @Autowired
与 @Qualifier
,因为它更加强大。从一个框架到另一个框架的转移被认为是非常不可能的,如果不是神话的话,尤其是在 Spring 的情况下。
@Autowired
和@Qualifier
注解比JSR标准的@Resource
注解更加强大(例如,使用@Autowired(required=false)
时可以处理可选依赖项。而使用@Resource
无法实现此功能)。 - Stefan Haberl我想强调一下对于这个问题的回答中@Jules提出的有用链接:@Resource, @Autowired和@ Inject的Spring注入。 我鼓励您完整阅读它,但是这里是其有用性的快速摘要:
@Autowired
和 @Inject
@Resource
显式命名您的组件 [@Component("beanName")]
使用带有name
属性的@Resource
[@Resource(name="beanName")]
@Qualifier
?除非您要创建一组类似的bean列表,否则避免使用@Qualifier
注释。例如,您可能希望使用特定的@Qualifier
注释标记一组规则。这种方法使将一组规则类注入到可用于处理数据的列表中变得简单。
为特定的包扫描组件[context:component-scan base-package="com.sourceallies.person"]
。虽然这会导致更多的component-scan
配置,但它减少了您向Spring上下文添加不必要组件的可能性。
这是我从Spring 3.0.x参考手册中得到的内容:
提示
如果您想通过名称表示注释驱动的注入,请不要主要使用@Autowired,即使它在技术上可以通过@Qualifier值引用bean名称。相反,使用JSR-250 @Resource注释,其在语义上定义为通过其唯一名称标识特定目标组件,声明类型对匹配过程无关。
作为此语义差异的具体后果,本身定义为集合或映射类型的bean不能通过@Autowired进行注入,因为类型匹配不适用于它们。对于这样的bean,请使用@Resource,通过唯一名称引用特定的集合或映射bean。
@Autowired适用于字段、构造函数和多参数方法,允许通过参数级别的限定符注释进行缩小范围。相比之下,@Resource仅支持具有单个参数的字段和bean属性设置器方法。因此,如果您的注入目标是构造函数或多参数方法,请坚持使用限定符。
@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
希望能对某人有所帮助 :)
两者都很好。使用Resource的优点在于,将来如果您想要使用除Spring之外的另一个DI框架,您的代码更改会更简单。而使用Autowired会使您的代码与Spring的DI紧密耦合。
当您从这两个注释的基类进行严格分析时,您将意识到以下差异。
@Autowired
使用AutowiredAnnotationBeanPostProcessor
注入依赖项。
@Resource
使用CommonAnnotationBeanPostProcessor
注入依赖项。
尽管它们使用不同的后处理器类,但它们的行为几乎相同。 关键差异在于它们的执行路径,我已经在下面突出显示了它们。
@Autowired / @Inject
1.按类型匹配
2.限定符限制
3.按名称匹配
@Resource
1.按名称匹配
2.按类型匹配
3.通过限定符进行限制(如果按名称找到匹配项,则忽略)
使用@Resource
,您可以进行bean自我注入,这可能是必要的,以便运行由bean后处理器添加的所有额外逻辑,如事务或安全相关内容。
在Spring 4.3+中,@Autowired
也能够实现这一点。
@Resource
经常被高级对象使用,这些对象是通过JNDI定义的。 @Autowired
或@Inject
将被更常见的bean使用。
据我所知,这不是一个规范,甚至不是一个约定。这更像是标准代码使用这些注解的逻辑方式。