@Autowired 和 @Resource 注解的区别?
结论先行:@Autowired 是 Spring 自有注解,由 AutowiredAnnotationBeanPostProcessor 处理,默认按类型(byType)注入,找不到唯一候选时再按名称收敛,另有 required 开关;@Resource 是 JSR-250 标准注解,由 CommonAnnotationBeanPostProcessor 处理,默认按名称(byName)注入,名字取字段名或 name 属性,找不到才回退按类型。二者都是"依赖注入的语法糖",但解析策略、来源、可标注位置、缺省行为都不同。
一、逐项对比
| 维度 | @Autowired | @Resource |
|---|---|---|
| 规范来源 | Spring 专有(org.springframework.beans.factory.annotation) | JSR-250(jakarta.annotation / 旧 javax.annotation) |
| 后置处理器 | AutowiredAnnotationBeanPostProcessor | CommonAnnotationBeanPostProcessor |
| 匹配策略 | 先 byType,多个候选再按字段/参数名或 @Qualifier 收窄 | 先 byName,按名字找不到才 byType |
| 名字来源 | @Qualifier("x")、参数名、字段名 | name 属性 → 否则字段名 |
| 是否必需 | 可 required=false,允许为 null | 无 required 属性,找不到就启动失败 |
| 可标注位置 | 构造器、方法、参数、字段、注解 | 字段、setter 方法、类(作为类级资源) |
| 多实现时 | 需 @Qualifier 或字段名匹配 | 用 name 指定更直观 |
| 与 Spring 耦合 | 高 | 低,可替换实现 |
二、匹配过程
@Autowired 注入 UserService:
① 按类型找候选 → 命中 1 个:直接注入
→ 命中 0 个:required=true 抛 NoSuchBeanDefinitionException
→ 命中多个:用 @Qualifier / 字段名 / @Primary 收窄
@Resource(name="userService") 注入:
① 按名字找 → 命中:注入
→ 未命中:回退按类型找 → 命中 1 个:注入
→ 多个或 0 个:抛异常
三、代码对照
@Service
public class OrderService {
// 推荐:构造器注入,字段 final,依赖显式、易于单测
private final PayService payService;
private final NotifyService notifyService;
public OrderService(PayService payService,
@Qualifier("smsNotify") NotifyService notifyService) {
this.payService = payService;
this.notifyService = notifyService; // 多个实现用 @Qualifier 收窄
}
// @Resource 适合"按 Bean 名取",比如策略实现按名字区分
@Resource(name = "alipayStrategy")
private PayStrategy alipay;
// @Autowired 的 required=false:允许容器里没有这个 Bean
@Autowired(required = false)
private Optional<MetricsReporter> reporter;
}
// 同名多实现时的两种收窄写法
@Component("smsNotify")
public class SmsNotifyService implements NotifyService { }
@Component("mailNotify")
public class MailNotifyService implements NotifyService { }
@Resource(name = "mailNotify") // 名字精确命中
private NotifyService notify;
四、什么时候选哪个
- 项目已统一用 Spring 技术栈、依赖构造器注入 → 用
@Autowired(构造器上只有一个构造器时甚至可省略); - 需要按 Bean 名注入、或代码要尽量少依赖 Spring API → 用
@Resource; - 存在多实现且语义就是"选某个具名策略" →
@Resource(name=...)比@Autowired + @Qualifier更直白; - 三者混用时注意:
@Autowired与@Resource标在同一字段上,@Resource生效(CommonAnnotationBeanPostProcessor优先级更高)。
五、常见追问
- 问:为什么推荐构造器注入? 依赖不可变(final)、启动即暴露缺失依赖、循环依赖会直接报错而不是靠三级缓存掩盖、单测无需容器。
- 问:字段名参与匹配吗? 会。
@Autowired在多个候选时会退化用字段名/参数名匹配,这依赖编译时保留参数名(-parameters),所以别把它当稳定契约,显式@Qualifier更可靠。 - 问:
@Autowired能注List<T>吗? 能,容器会注入所有T的实现,配合@Order可控制顺序,这是策略模式的常用写法。 - 问:JDK 11 之后
@Resource报找不到符号? Spring Boot 3 已切到jakarta.annotation.Resource,老项目需显式引入jakarta.annotation-api或javax.annotation-api。
小结
一句话区分:@Autowired 是"按类型找,多个再挑名字",@Resource 是"按名字找,找不到再看类型"。答题时补上处理器、来源、required、可标注位置四个维度,再说明"生产代码优先构造器注入",就不会被追问倒。