Spring Injection with @Resource, @Autowired and @Inject

本文深入探讨了Spring中用于依赖注入的三个注解:@Resource、@Autowired和@Inject的行为和区别,通过实验展示了它们在解决多匹配类型、字段名、字段类型、默认名称限定符、全名限定符以及注入列表中的表现。

Spring Injection with @Resource, @Autowired and @Inject


[这个2011年的文章,关于这个主题非常好的一篇文章  http://blogs.sourceallies.com/2011/08/spring-injection-with-resource-and-autowired/]

Overview

I’ve been asked several times to explain the difference between injecting Spring beans with ‘@Resource’, ‘@Autowired’, and ‘@Inject’. While I received a few opinions from colleagues and read a couple of posts on this topic I didn’t feel like I had a complete picture.

Annotations
AnnotationPackageSource
@Resource javax.annotation Java
@Inject javax.inject Java
@Qualifier javax.inject Java
@Autowired org.springframework.bean.factory Spring

In order to explore the behavior of each annotation I fired up Spring Tool Suite and started debugging the code. I used Spring 3.0.5.RELEASE in my research. The following is a summary of my findings.

The Code

I wanted to know how ‘@Resource’, ‘@Autowired’, and ‘@Inject’ resolved dependencies. I created an interface called ‘Party’ and created two implementations classes. This allowed me to inject beans without using the concrete type. This provided the flexibility I needed to determine how Spring resolves beans when there are multiple type matches.

public interface Party {
 
}

‘Person’ is a component and it implements ‘Party’.

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


‘Organization’ is a component and it implements ‘Party’.

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


I setup a Spring context that scans both of these packages for beans marked with ‘@Component’.

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

Tests

Test 1: Ambiguous Beans

In this test I injected a ‘Party’ bean that has multiple implementations in the Spring context.

@Resource
private Party party;

@Autowired
private Party party;

@Inject
private Party party;

In all three cases a ‘NoSuchBeanDefinitionException’ is thrown. While this exception’s name implies that no beans were found, the message explains that two beans were found. All of these annotations result in the same exception.

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

Test 2: Field Name

In this test I named the Party field person. By default beans marked with ‘@Component’ will have the same name as the class. Therefore the name of the class ‘Person’ is person.

@Resource
private Party person;

@Autowired
private Party person;


@Inject
private Party person;

‘@Resource’ can also take an optional ‘name’ attribute. This is equivalent to the ‘@Resource’ code above. In this case the field variable name remains ‘party’. There is no equivalent syntax for ‘@Autowired’ or ‘@Inject’. Instead you would have to use a ‘@Qualifier’. This syntax will be covered later.

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


All four of these styles inject the ‘Person’ bean.

Test 3: Field Type

In this test I changed the type to be a ‘Person’.

@Resource
private Person party;


@Autowired
private Person party;


@Inject
private Person party;


All of these annotations inject the ‘Person’ bean.

Test 4: Default Name Qualifier

In this test I use a ‘@Qualifier’ annotation to point to the default name of the ‘Person’ component.

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


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

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

All of these annotations inject the ‘Person’ bean.

Test 5: Qualified Name

I added a ‘@Qualifier’ annotation to the ‘Person’ class

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


In this test I use a ‘@Qualifier’ annotation to point to the qualified name of the ‘Person’ component.

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

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

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


All of these annotations inject the ‘Person’ bean.

Test 6: List of Beans

In this test I inject a list of beans.

@Resource
private List<Party> parties;

@Autowired
private List<Party> parties;

@Inject
private List<Party> parties;


All of these annotations inject 2 beans into the list. This can also be accomplished with a ‘@Qualifier’. Each bean marked with a specific qualifier will be added to the list.

Test 7: Conflicting messages

In this test I add a bad ‘@Qualifier’ and a matching field name.

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



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


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


In this case the field marked with ‘@Resource’ uses the field name and ignores the ‘@Qualifier’. As a result the ‘Person’ bean is injected.

However the ‘@Autowired’ and ‘@Inject’ field throw a ‘NoSuchBeanDefinitionException’ error because it can not find a bean that matches the ‘@Qualifier’.

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)}

Conclusions

With the exception of test 2 & 7 the configuration and outcomes were identical. When I looked under the hood I determined that the ‘@Autowired’ and ‘@Inject’ annotation behave identically. Both of these annotations use the ‘AutowiredAnnotationBeanPostProcessor’ to inject dependencies. ‘@Autowired’ and ‘@Inject’ can be used interchangeable to inject Spring beans. However the ‘@Resource’ annotation uses the ‘CommonAnnotationBeanPostProcessor’ to inject dependencies. Even though they use different post processor classes they all behave nearly identically. Below is a summary of their execution paths.

@Autowired and @Inject

  1. Matches by Type
  2. Restricts by Qualifiers
  3. Matches by Name

@Resource

  1. Matches by Name
  2. Matches by Type
  3. Restricts by Qualifiers (ignored if match is found by name)

While it could be argued that ‘@Resource’ will perform faster by name than ‘@Autowired’ and ‘@Inject’ it would be negligible. This isn’t a sufficient reason to favor one syntax over the others. I do however favor the ‘@Resource’ annotation for it’s concise notation style.

@Resource(name="person")

@Autowired
@Qualifier("person")

@Inject
@Qualifier("person")


You may argue that they can be equal concise if you use the field name to identify the bean name.

@Resource
private Party person;


@Autowired
private Party person;

@Inject
private Party person;


True enough, but what happens if you want to refactor your code? By simply renaming the field name you’re no longer referring to the same bean. I recommend the following practices when wiring beans with annotations.

Spring Annotation Style Best Practices

  1. Explicitly name your component [@Component(“beanName”)]
  2. Use ‘@Resource’ with the ‘name’ attribute [@Resource(name=”beanName”)]
  3. Avoid ‘@Qualifier’ annotations unless you want to create a list of similar beans. For example you may want to mark a set of rules with a specific ‘@Qualifier’ annotation. This approach makes it simple to inject a group of rule classes into a list that can be used for processing data.
  4. Scan specific packages for components [context:component-scan base-package=”com.sourceallies.person”]. While this will result in more component-scan configurations it reduces the chance that you’ll add unnecessary components to your Spring context.

Following these guidelines will increase the readability and stability of your Spring annotation configurations.


<think>首先,用户的问题是:我想理解不同Java注解在依赖注入中的区别。请问Java中@Autowired@Inject@Resource注解的区别。 根据系统级指令,我需要: - 所有行内数学表达式使用$...$格式。 - 独立公式使用$$...$$格式并单独成段。 - LaTeX语法正确。 - 使用中文回答。 - 生成相关问题。 - 回答中引用的段落末尾自然地添加引用标识,例如:[^1]。 - 回答结构清晰,帮助用户逐步解决问题,保证回答真实可靠。 - 参考站内引用:引用[1]到[5]是关于Spring注解的,但用户的问题是关于Java注解在依赖注入中的区别,具体是@Autowired, @Inject, @Resource。 用户提供的引用: - [^1]: 关于@Autowired@Inject的区别。 - [^2]: 处理这些注解的实现类。 - [^3]: 文章目录,包括@Autowired, @Resource, @Qualifier, @Inject。 - [^4]: Java中三个注解的区别。 - [^5]: 示例代码。 我需要基于这些引用和一般知识来回答,因为指令说“上述引用仅供参考”,但我应该参考用户上一次的问题和我的回答。用户这是第一次提问,所以我需要基于引用和标准知识。 关键点: - @Autowired: Spring框架特定的注解。 - @Inject: Java EE标准注解,基于JSR-330。 - @Resource: Java EE标准注解,基于JSR-250。 区别: 1. **来源**: - @Autowired: Spring框架的一部分。 - @Inject: Java标准(JSR-330),由CDI支持。 - @Resource: Java标准(JSR-250),用于资源注入。 2. **注入方式**: - @Autowired: 默认按类型注入。如果有多个bean,需要配合@Qualifier或按名称。 - @Inject: 类似@Autowired,按类型注入,是Java标准。 - @Resource: 默认按名称注入,名称通过name属性指定。 3. **处理方式**: - Spring中,@Autowired由AutowiredAnnotationBeanPostProcessor处理。 - @Inject由同一个处理器处理(因为@Inject是标准)。 - @Resource由CommonAnnotationBeanPostProcessor处理。 4. **其他特性**: - @Autowired可以用于字段、构造函数、方法。 - @Inject类似。 - @Resource可以用于字段和方法。 - @Autowired@Inject支持可选注入(required=false)。 - @Resource有name属性指定bean名称。 结构回答: 1. **介绍**:简要解释依赖注入和这些注解的作用。 2. **区别**:逐步比较每个注解的来源、注入方式、使用场景等。 3. **示例**:提供简单代码示例(如果需要,但用户引用中有示例)。 4. **总结**:总结关键区别。 5. **生成相关问题**:在最后添加相关问题。 使用中文。 数学表达式:用户问题可能不需要数学,但如果有,就用LaTeX格式。例如,如果提到公式。 引用:在回答中,当引用特定段落时,添加引用标识。例如,基于引用[1],@Autowired@Inject行为类似。 回答结构: - 标题:Java中@Autowired@Inject@Resource注解的区别 - 正文: - 依赖注入概述 - 每个注解的详细解释 - 比较表格或列表 - 示例 - 相关问题 确保引用自然添加。</think>### Java中@Autowired@Inject@Resource注解的区别 在Java开发中,依赖注入(Dependency Injection, DI)是一种常见的设计模式,用于解耦组件之间的依赖关系,提高代码的可测试性和可维护性。Spring框架提供了多个注解来简化依赖注入的实现,包括`@Autowired`、`@Inject`和`@Resource`。这些注解虽然功能相似,但在来源、注入方式、处理机制和适用场景上存在显著差异。下面我将逐步解释它们的区别,帮助您清晰理解。 #### 1. **来源和标准** - **@Autowired**:这是Spring框架特有的注解,属于`org.springframework.beans.factory.annotation`包。它不遵循任何Java EE标准,而是Spring自定义的实现[^1][^4]。 - **@Inject**:这是一个Java标准注解,基于JSR-330(Java Dependency Injection规范)。它由`javax.inject`包提供,是CDI(Contexts and Dependency Injection)的一部分,旨在提供跨框架的统一依赖注入支持[^1][^3]。 - **@Resource**:这也是Java标准注解,基于JSR-250(Common Annotations规范)。它由`javax.annotation`包提供,主要用于资源注入(如数据库连接或JNDI资源),但也可用于一般依赖注入[^2][^4]。 简单来说,`@Autowired`是Spring专属,而`@Inject`和`@Resource`是Java EE标准注解,具有更好的跨框架兼容性。 #### 2. **注入方式和匹配规则** 依赖注入的核心是Bean的匹配方式,即如何找到并注入依赖对象。以下是每个注解的默认行为: - **@Autowired**: - 默认按**类型(Type)** 匹配:Spring容器会查找与字段或参数类型匹配的Bean。如果存在多个相同类型的Bean,则需要配合`@Qualifier`注解指定名称,否则会抛出异常。 - 支持按名称注入:如果字段或参数名与Bean名称一致,Spring会优先使用名称匹配(但这不是默认行为,需显式配置)。 - 可选注入:通过`required=false`属性,可以标记依赖为可选(即如果找不到Bean,不报错)。 - 示例代码: ```java import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; @Service public class UserService { @Autowired // 按类型注入UserRepository private UserRepository userRepo; } ``` - **@Inject**: - 行为与`@Autowired`几乎相同:默认按**类型**匹配,也支持`@Qualifier`(或JSR-330的`@Named`)来指定名称。 - 主要区别:`@Inject`是Java标准,不依赖Spring框架,因此更适用于非Spring环境(如Jakarta EE或Quarkus)。在Spring中,它被`AutowiredAnnotationBeanPostProcessor`处理,与`@Autowired`共享相同的执行路径[^1][^2]。 - 示例代码: ```java import javax.inject.Inject; import javax.inject.Named; public class OrderService { @Inject // 按类型注入PaymentProcessor @Named("creditCardProcessor") // 使用@Named指定Bean名称 private PaymentProcessor processor; } ``` - **@Resource**: - 默认按**名称(Name)** 匹配:Spring容器会优先根据字段或参数名查找Bean(例如,字段名`userRepo`对应Bean名`userRepo`)。如果名称不匹配,则回退到按类型匹配。 - 支持`name`属性:可以直接指定Bean名称(如`@Resource(name="myBean")`),避免歧义。 - 不支持可选注入:没有`required`属性,如果找不到Bean,会抛出异常。 - 示例代码: ```java import javax.annotation.Resource; public class ProductService { @Resource(name = "inventoryRepo") // 显式指定Bean名称 private InventoryRepository repo; } ``` #### 3. **处理机制和Spring支持** - **处理类**: - `@Autowired`和`@Inject`由同一个Spring处理器处理:`AutowiredAnnotationBeanPostProcessor`。这意味着在Spring中,它们的行为高度一致,按优先顺序匹配:类型 → 限定符 → 名称[^1][^2]。 - `@Resource`由另一个处理器处理:`CommonAnnotationBeanPostProcessor`,它专注于JSR-250标准注解[^2][^4]。 - **适用场景**: - 使用`@Autowired`:推荐在纯Spring项目中使用,因为它与Spring生态集成更深(如支持`@Qualifier`和SpEL表达式)。 - 使用`@Inject`:适合需要跨框架兼容性的场景(例如,从Spring迁移到Jakarta EE),或在非Spring容器中。 - 使用`@Resource`:常用于资源注入(如数据库连接池),或在需要强名称匹配时简化配置。 #### 4. **总结对比** 下表总结了关键区别: | 特性 | @Autowired | @Inject | @Resource | |--------------------|---------------------------|---------------------------|---------------------------| | **来源** | Spring框架专属 | Java标准 (JSR-330) | Java标准 (JSR-250) | | **默认匹配方式** | 按类型 | 按类型 | 按名称 | | **支持名称指定** | 需配合@Qualifier | 需配合@Named | 直接通过name属性 | | **可选注入** | 支持 (required=false) | 支持 | 不支持 | | **处理类** | AutowiredAnnotationBeanPostProcessor | 同@Autowired | CommonAnnotationBeanPostProcessor | | **最佳适用场景** | Spring项目 | 跨框架项目 | 资源注入或名称优先匹配 | #### 5. **实际应用建议** - 在Spring项目中,优先使用`@Autowired`,因为它与Spring特性(如AOP或Profile)无缝集成。 - 如果需要标准化代码,减少框架依赖,选择`@Inject`或`@Resource`。 - 注意:所有注解都支持字段、构造函数和方法注入。但避免过度使用,以免增加配置复杂性[^3][^5]。 通过以上分析,您应该能清晰区分这些注解。如果您有具体代码场景,可以提供更多细节,我可以给出针对性建议。 ### 相关问题 1. 如何在Spring中处理多个相同类型的Bean的注入问题? 2. @Qualifier和@Named注解在实际项目中如何配合使用? 3. 依赖注入与手动注入(如使用new关键字)相比有哪些优缺点? 4. 在非Spring框架(如Jakarta EE)中,如何实现依赖注入? 5. Spring Boot中这些注解的使用有什么变化或最佳实践?[^3][^4]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值