快速对比表
| 特性 | @Autowired | @Resource |
|---|---|---|
| 来源 | Spring 框架 | Java 标准(JSR-250) |
| 装配方式 | 按类型(byType)优先 | 按名称(byName)优先 |
| 所属包 | org.springframework.beans.factory.annotation | javax.annotation |
| 依赖注入顺序 | 1. 按类型匹配 2. 如果多个,按名称匹配 3. 使用 @Qualifier 指定 | 1. 按名称匹配 2. 如果找不到,按类型匹配 |
与 @Qualifier 配合 | 需要配合使用 | 不需要,直接用 name 属性 |
| 属性 | required(默认 true) | name、type |
| 适用范围 | 字段、构造器、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,按类型注入 | @Autowired | Spring 原生,功能完整 |
| 多个同类型 Bean | @Autowired + @Qualifier | 更灵活,支持更多配置 |
| 按名称注入 | @Resource | 更直观,代码意图清晰 |
| 需要可选注入 | @Autowired(required=false) | @Resource 不支持 |
| 跨框架兼容性 | @Resource | Java 标准,不依赖 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,代码更简洁直观