一、核心区别对比
| 维度 | @Autowired | @Resource |
|---|---|---|
| 来源 | Spring原生注解(org.springframework.beans.factory.annotation) | Java EE标准注解(JSR-250,javax.annotation) |
| 默认注入策略 | 按类型(byType)匹配 | 按名称(byName)匹配 |
| 是否支持构造器注入 | ✅ 支持 | ❌ 仅支持字段/Setter方法注入 |
| 消除歧义方式 | 需配合@Qualifier指定Bean名称 | 直接通过name或type属性指定 |
| 是否必需 | required=true(默认),可设为false允许null | 无required属性,未匹配时抛异常 |
| 跨框架兼容性 | 仅Spring生态适用 | 支持所有JSR-250容器(如Jakarta EE) |
⚙️ 二、实现原理详解
1. 处理器与工作流程
-
@Autowired
由AutowiredAnnotationBeanPostProcessor处理:-
扫描阶段:解析类中所有
@Autowired注解(字段/构造器/方法); -
注入阶段:
- 按类型查找候选Bean → 若唯一则注入;
- 若多个匹配,按字段名或
@Qualifier指定名称筛选; - 未匹配且
required=true时抛NoSuchBeanDefinitionException。
-
-
@Resource
由CommonAnnotationBeanPostProcessor处理:-
名称优先策略:
- 若指定
name,直接按名称查找Bean; - 未指定时,取字段/方法名作为默认名称;
- 若指定
-
类型回退策略:名称未匹配时,按类型查找唯一Bean;
-
JNDI支持:可查找非Spring管理的资源(如数据源)。
-
💡 三、典型场景与使用建议
1. 推荐使用@Autowired的场景
- 构造器注入:强制依赖不可变对象(如数据库连接);
- 类型安全优先:结合
@Qualifier明确指定Bean; - 深度集成Spring:需与AOP、事务管理等联动。
2. 推荐使用@Resource的场景
- 名称明确匹配:Bean名称与字段名一致时更简洁;
- 跨环境兼容:项目可能迁移至非Spring容器(如Jakarta EE);
- JNDI资源注入:需注入数据源等外部资源。
3. 解决多实现类冲突
// 方案1:@Autowired + @Qualifier
@Autowired
@Qualifier("mysqlRepo")
private UserRepository repository;
// 方案2:@Resource指定名称
@Resource(name = "mysqlRepo")
private UserRepository repository;
⚠️ 四、常见问题与避坑指南
-
歧义注入异常
@Autowired遇多个同类型Bean需@Qualifier;@Resource字段名需与Bean名称一致,否则按类型可能失败。
-
空指针风险
@Autowired(required=false)允许注入null,需判空;@Resource未匹配时直接抛异常,需确保Bean存在。
-
循环依赖问题
两者均可能触发,建议用构造器注入或@Lazy延迟初始化。
💎 总结
| 注解 | 适用场景 | 不适用场景 |
|---|---|---|
@Autowired | Spring深度集成、构造器注入、类型驱动开发 | 需解耦Spring或名称明确匹配的场景 |
@Resource | 跨框架兼容、JNDI资源、名称与字段一致的简单注入 | 构造器注入或需灵活处理null的场景 |
设计启示:
- 强Spring生态选
@Autowired,灵活性更高;- 需避免厂商锁定选
@Resource,标准化更优。
源码级理解可参考AutowiredAnnotationBeanPostProcessor与CommonAnnotationBeanPostProcessor的实现差异。