@Autowired vs @Resource

96 阅读4分钟

快速对比表

特性@Autowired@Resource
来源Spring 框架Java 标准(JSR-250)
装配方式按类型(byType)优先按名称(byName)优先
所属包org.springframework.beans.factory.annotationjavax.annotation
依赖注入顺序1. 按类型匹配
2. 如果多个,按名称匹配
3. 使用 @Qualifier 指定
1. 按名称匹配
2. 如果找不到,按类型匹配
@Qualifier 配合需要配合使用不需要,直接用 name 属性
属性required(默认 true)nametype
适用范围字段、构造器、Setter 方法字段、Setter 方法

详细对比

1. 功能上基本等价

当指定 Bean 名称时,两者功能完全相同:

// 方式 1:@Autowired + @Qualifier
@Autowired
@Qualifier("xxxOpenAPIClient")
private OpenAPIClient client;

// 方式 2:@Resource(name=...)
@Resource(name = "xxxOpenAPIClient")
private OpenAPIClient client;

// ✅ 两者完全等价

2. 关键区别:匹配顺序不同

@Autowired + @Qualifier 的流程:

1. 看 @Qualifier 指定的名称 → 找到 Bean
2. 如果 @Qualifier 没指定 → 按字段类型查找
3. 如果找到多个同类型 Bean → 按字段名二次匹配
4. 如果还是找不到 → 报错

@Resource 的流程:

1. 看 @Resource(name=...) 指定的名称 → 找到 Bean
2. 如果没指定 name → 按字段名查找
3. 如果字段名找不到 → 按字段类型查找
4. 如果还是找不到 → 报错

3. 实际场景对比

场景 A:指定 Bean 名称(完全等价)

// 方式 1:@Autowired + @Qualifier
@Autowired
@Qualifier("xxxOpenAPIClient")
private OpenAPIClient client;

// 方式 2:@Resource(name=...)
@Resource(name = "xxxOpenAPIClient")
private OpenAPIClient client;

// ✅ 两者完全等价

场景 B:按字段名自动匹配(不等价)

// 方式 1:@Autowired(需要字段名与 Bean 名称相同)
@Autowired
private ServiceImpl serviceImpl;  // 字段名 = Bean 名称

// 方式 2:@Resource(自动按字段名匹配)
@Resource
private ServiceImpl serviceImpl;  // 自动按字段名匹配

// ✅ 两者都能工作,但原理不同
// @Autowired 是按类型匹配,然后按字段名二次匹配
// @Resource 是直接按字段名匹配

场景 C:多个同类型 Bean,无指定名称(不等价)

// 假设有两个 OpenAPIClient Bean:xxxOpenAPIClient 和 yyyOpenAPIClient

// 方式 1:@Autowired(会报错)
@Autowired
private OpenAPIClient client;  // ❌ 无法确定注入哪个 Bean

// 方式 2:@Resource(会按字段名匹配)
@Resource
private OpenAPIClient client;  // ❌ 字段名 "client" 不匹配任何 Bean 名称,报错

// 两者都会失败,但原因不同

场景 D:可选注入(只有 @Autowired 支持)

// @Autowired 支持可选注入
@Autowired(required = false)
private OptionalService optionalService;  // ✅ 如果 Bean 不存在,不会报错

// @Resource 不支持可选注入
@Resource
private OptionalService optionalService;  // ❌ 如果 Bean 不存在,会报错

完整对比矩阵

情况@Autowired + @Qualifier@Resource(name=...)是否等价
指定 Bean 名称✅ 按指定名称匹配✅ 按指定名称匹配✅ 等价
无指定,字段名 = Bean 名称✅ 按类型→字段名✅ 按字段名✅ 等价
无指定,字段名 ≠ Bean 名称❌ 报错❌ 报错✅ 等价
多个同类型 Bean,无指定❌ 报错❌ 报错✅ 等价
可选注入required=false❌ 不支持❌ 不等价

最佳实践

推荐用法

1. 单个 Bean,按类型注入

@Autowired
private UserMapper userMapper;  // 只有一个 UserMapper Bean

2. 多个同类型 Bean,需要指定

// 推荐:使用 @Resource(name=...)
@Resource(name = "xxxOpenAPIClient")
private OpenAPIClient client;

// 或者:使用 @Autowired + @Qualifier
@Autowired
@Qualifier("xxxOpenAPIClient")
private OpenAPIClient client;

3. 按名称注入

// 推荐:@Resource 更直观
@Resource
private DrillPlanService drillPlanService;  // 自动按字段名匹配

4. 可选注入

// 只能用 @Autowired
@Autowired(required = false)
private OptionalService optionalService;

选择建议

场景推荐原因
单个 Bean,按类型注入@AutowiredSpring 原生,功能完整
多个同类型 Bean@Autowired + @Qualifier更灵活,支持更多配置
按名称注入@Resource更直观,代码意图清晰
需要可选注入@Autowired(required=false)@Resource 不支持
跨框架兼容性@ResourceJava 标准,不依赖 Spring

代码示例

XML 配置

<bean id="xxxOpenAPIClient" 
      class="com.example.service.OpenAPIClientFactory" 
      factory-method="initOpenAPIClient">
    <constructor-arg name="timeout" value="10000"/>
</bean>

注入方式对比

方式 1:@Autowired + @Qualifier

@Autowired
@Qualifier("xxxOpenAPIClient")
private OpenAPIClient client;

方式 2:@Resource(name=...)

@Resource(name = "xxxOpenAPIClient")
private OpenAPIClient client;

方式 3:@Resource(按字段名匹配)

@Resource
private OpenAPIClient xxxOpenAPIClient;  // 字段名必须与 Bean 名称相同

总结

何时使用 @Autowired

  • ✅ 需要按类型注入
  • ✅ 需要可选注入(required=false
  • ✅ 需要在构造器或 Setter 方法上使用
  • ✅ 需要更多的 Spring 特性支持

何时使用 @Resource

  • ✅ 需要按名称注入
  • ✅ 代码意图是明确指定 Bean 名称
  • ✅ 需要跨框架兼容性(Java 标准)
  • ✅ 代码更简洁(一个注解 vs 两个注解)

核心结论

  • 当指定 Bean 名称时@Resource(name=...) 等价于 @Autowired + @Qualifier
  • 当不指定名称时:两者的匹配顺序不同,可能导致不同的结果
  • 推荐:优先使用 @Resource,代码更简洁直观