@Autowired 和 @Resource 注解的区别?
2026年02月01日
一则或许对你有用的小广告
欢迎 加入小哈的星球 ,你将获得: 专属的项目实战(已更新的所有项目都能学习) / 1v1 提问 / Java 学习路线 / 学习打卡 / 每月赠书 / 社群讨论
- 新开坑项目: 《Spring AI 项目实战(问答机器人、RAG 增强检索、联网搜索)》 正在持续爆肝中,基于
Spring AI + Spring Boot3.x + JDK 21..., 点击查看; - 《从零手撸:仿小红书(微服务架构)》 已完结,基于
Spring Cloud Alibaba + Spring Boot3.x + JDK 17..., 点击查看项目介绍; 演示链接: http://116.62.199.48:7070/; - 《从零手撸:前后端分离博客项目(全栈开发)》 2 期已完结,演示链接: http://116.62.199.48/
面试考察点
面试官问出这个问题,主要想考察以下几个层面:
- 对主流依赖注入(DI)注解的基础掌握:候选人是否清楚这两个注解的基本用途,即它们都是用来进行依赖注入的。
- 对两者核心差异的精准理解:这不仅仅是记住区别,更是考察候选人是否理解 Spring 框架与 Java EE 标准之间的关系,以及不同设计哲学下的实现选择。
- 在实际开发中的选型和应用能力:面试官想知道你是否能根据具体场景(例如,按类型还是按名称注入,是否需要处理多Bean候选者)做出合适的选择,并了解其背后的原理。
- 是否关注过最佳实践和版本演进:例如,是否了解 Spring 官方当前更推荐构造函数注入,以及如何避免注解使用的常见陷阱。
核心答案
@Autowired 和 @Resource 都是用来完成依赖注入的注解,但它们在来源、默认注入方式、以及处理 “有多个匹配Bean” 时的策略上存在关键区别。
| 特性 | @Autowired | @Resource |
|---|---|---|
| 来源 | Spring 框架原生注解 (org.springframework.beans.factory.annotation) | Java EE(JSR-250)标准注解 (javax.annotation),现由 Jakarta EE 维护。Spring 对其提供了支持。 |
| 默认注入方式 | 按类型(byType)。 | 按名称(byName)。如果未指定名称,则回退到按类型。 |
| 处理“多个Bean”的方式 | 1. 与 @Qualifier 注解配合,指定 Bean 的名称。2. 如果存在多个同类型 Bean,必须通过上述方式消除歧义,否则会抛出 NoUniqueBeanDefinitionException。 | 1. 优先使用其 name 属性指定的名称进行匹配。2. 若未指定 name,则使用字段或 setter 方法的名称作为 Bean 名查找。3. 若按名称未找到,才回退到按类型,此时若仍有多个,则报错。 |
是否支持 required | 支持。@Autowired(required = false) 表示注入是可选的,找不到 Bean 时不会报错(注入 null)。 | 不支持。但可以通过结合 @Nullable(Spring 5+)或使用 Java 8 的 Optional 包装达到类似效果。 |
| 适用场景 | 典型 Spring 项目,强调按类型注入的松耦合。 | 需要按名称注入,或希望代码对 Spring 框架的依赖更轻(因为是标准注解)。 |
简单来说:想按类型注入用 @Autowired,想按名称注入用 @Resource。
深度解析
原理与机制
@Autowired 由 Spring 的 AutowiredAnnotationBeanPostProcessor 处理。它的核心逻辑是 “按类型匹配”。在 Spring 容器启动、装配 Bean 时,它会寻找与目标字段/方法参数类型匹配的 Bean。这个过程是 Spring 依赖注入的核心体现。
@Resource 由 CommonAnnotationBeanPostProcessor 处理。它的处理逻辑更符合 Java EE 的直觉:先按名,再按型。这种设计使得它在处理一些名称明确、需要精准指向的场景时更加直观。
代码示例
假设我们有以下两个同类型的 Bean:
@Repository("userDaoImplA") // 指定 Bean 名称为 “userDaoImplA”
public class UserDaoImplA implements UserDao { ... }
@Repository("userDaoImplB") // 指定 Bean 名称为 “userDaoImplB”
public class UserDaoImplB implements UserDao { ... }
场景一:使用 @Autowired
@Component
public class UserService {
// 方式1:直接使用,会因找到两个 UserDao 类型的 Bean 而报错。
// @Autowired
// private UserDao userDao;
// 方式2:正确方式,配合 @Qualifier 指定名称
@Autowired
@Qualifier("userDaoImplA")
private UserDao userDao;
}
场景二:使用 @Resource
@Component
public class UserService {
// 方式1:使用 name 属性明确指定
@Resource(name = "userDaoImplA")
private UserDao userDao;
// 方式2:不指定 name,则使用字段名 `userDao` 去查找 Bean,找不到,报错。
// @Resource
// private UserDao userDao; // 错误!
// 方式3:将字段名改为与其中一个 Bean 名称一致
@Resource
private UserDao userDaoImplA; // 成功注入 UserDaoImplA
}
最佳实践与注意事项
- 现代 Spring 开发的首选:对于必须的依赖,Spring 官方推荐使用构造函数注入(在构造方法上使用
@Autowired,Spring 4.3 后单构造方法可省略)。这种方式能保证依赖不可变,且便于测试。 - 清晰的命名:使用
@Resource时,保持注入的字段名与目标 Bean 的名称一致,可以使代码意图更清晰。 - 避免混用:在同一个项目中,建议团队统一注入风格,避免
@Autowired和@Resource随意混用,增加理解和维护成本。 - 可选依赖:对于可选的依赖,使用
@Autowired(required = false)或Optional<T>进行包装是更 Spring 风格的做法。
常见误区
- 误区一:认为
@Resource是 Spring 注解。它是 Java/Jakarta EE 标准,Spring 只是 “支持” 它。了解这一点有助于理解其设计初衷(与 EJB 等传统 Java EE 组件兼容)。 - 误区二:认为
@Resource一定按名称注入。准确说,它是 “优先” 按名称,名称找不到时会回退到按类型。如果按类型找到多个,同样会失败。 - 误区三:过度依赖字段注入。无论是
@Autowired还是@Resource,直接标注在字段上虽然方便,但会绕过 Spring 的实例化流程(如通过反射直接设置),不利于封装和测试。构造函数注入或 Setter 注入是更优的选择。
总结
@Autowired 是 Spring 亲生的 “按类型” 注入能手,需要搭配 @Qualifier 来处理名称问题;而 @Resource 是 Java 标准出身的“先名后型”多面手。理解它们的区别,能帮助你在 Spring 项目中更优雅、更精准地进行依赖管理。在实际开发中,遵循构造函数注入的现代最佳实践,能让你的代码更加健壮和清晰。