
文章目录
-
- 一、前言
- 二、两者的来源与定位
- 三、共同点
- [四、`@Autowired` 注入机制详解](#四、
@Autowired注入机制详解) -
- [1. 按类型注入(byType)](#1. 按类型注入(byType))
- [2. 当有多个同类型 Bean 时](#2. 当有多个同类型 Bean 时)
- [3. 解决方案](#3. 解决方案)
-
- [(1)使用 `@Qualifier` 指定 Bean 名称:](#(1)使用
@Qualifier指定 Bean 名称:) - [(2)使用 `@Primary` 标记优先 Bean:](#(2)使用
@Primary标记优先 Bean:)
- [(1)使用 `@Qualifier` 指定 Bean 名称:](#(1)使用
- [4. 支持构造器注入、Setter 注入、字段注入](#4. 支持构造器注入、Setter 注入、字段注入)
- [5. 支持 `required` 属性](#5. 支持
required属性)
- [五、`@Resource` 注入机制详解](#五、
@Resource注入机制详解) -
- [1. 按名称注入(byName)](#1. 按名称注入(byName))
- [2. 若找不到匹配名称,则按类型注入(byType)](#2. 若找不到匹配名称,则按类型注入(byType))
- [3. 可通过属性显式指定 Bean 名称](#3. 可通过属性显式指定 Bean 名称)
- [4. 不支持 `@Primary` 和 `@Qualifier`](#4. 不支持
@Primary和@Qualifier)
- 六、注入顺序对比(核心差异)
- [七、在 Spring Boot 中的推荐实践](#七、在 Spring Boot 中的推荐实践)
- 八、实践建议
一、前言
在 Spring 开发中,依赖注入(Dependency Injection, DI) 是最核心的特性之一。
当我们要把一个 Bean 自动注入到另一个类中时,经常会看到两种注解:
java
@Autowired
private UserService userService;
java
@Resource
private UserService userService;
它们看起来效果相同,但实际上存在底层机制与使用细节的差异 。
下面将深入剖析两者的区别与最佳实践。
二、两者的来源与定位
| 注解 | 所属包 | 引入规范 | 依赖容器 |
|---|---|---|---|
@Autowired |
org.springframework.beans.factory.annotation |
Spring 框架 | Spring |
@Resource |
jakarta.annotation(或旧版 javax.annotation) |
JSR-250 标准 | Java EE(兼容 Spring) |
简而言之:
@Autowired→ Spring 专属注解@Resource→ Java 官方标准注解
💡 Spring 同时支持两者,但其注入规则不同。
三、共同点
在功能层面,它们都用于实现 依赖自动注入 (即不再手动 new 对象)。
示例:
java
@Service
public class OrderService {
@Autowired
private UserService userService;
public void createOrder() {
userService.notifyUser();
}
}
或使用 @Resource:
java
@Service
public class OrderService {
@Resource
private UserService userService;
public void createOrder() {
userService.notifyUser();
}
}
两种方式都能正常工作。
但区别在于:当容器中存在多个同类型 Bean 时,它们的注入逻辑完全不同。
四、@Autowired 注入机制详解
1. 按类型注入(byType)
Spring 会优先根据 类型(Type) 查找匹配的 Bean:
java
@Autowired
private UserService userService;
如果容器中存在唯一的 UserService 类型 Bean,就能正常注入。
2. 当有多个同类型 Bean 时
java
@Service
public class UserServiceA implements UserService {}
@Service
public class UserServiceB implements UserService {}
@Autowired
private UserService userService; // ❌ 报错:NoUniqueBeanDefinitionException
此时 Spring 不知道该注入哪一个。
3. 解决方案
(1)使用 @Qualifier 指定 Bean 名称:
java
@Autowired
@Qualifier("userServiceA")
private UserService userService;
(2)使用 @Primary 标记优先 Bean:
java
@Service
@Primary
public class UserServiceA implements UserService {}
4. 支持构造器注入、Setter 注入、字段注入
java
@Autowired
public OrderService(UserService userService) {
this.userService = userService;
}
或:
java
@Autowired
public void setUserService(UserService userService) {
this.userService = userService;
}
推荐使用 构造器注入 ------ 更利于单元测试与不可变设计。
5. 支持 required 属性
java
@Autowired(required = false)
private UserService userService;
如果容器中没有该 Bean,不会抛异常,而是注入 null。
五、@Resource 注入机制详解
1. 按名称注入(byName)
@Resource 默认优先根据 字段名(Name) 查找 Bean。
java
@Resource
private UserService userService;
Spring 会首先尝试匹配 Bean 名称为 "userService" 的对象。
2. 若找不到匹配名称,则按类型注入(byType)
如果容器中没有 "userService" 这个 Bean 名称,Spring 会退而求其次,按类型注入。
⚠️ 若存在多个相同类型 Bean,会抛出
NoUniqueBeanDefinitionException。
3. 可通过属性显式指定 Bean 名称
java
@Resource(name = "userServiceA")
private UserService userService;
这相当于
@Autowired + @Qualifier("userServiceA")。
4. 不支持 @Primary 和 @Qualifier
@Resource 是 Java 标准注解,不依赖 Spring 的扩展机制,因此不支持这两个注解。
六、注入顺序对比(核心差异)
| 步骤 | @Autowired |
@Resource |
|---|---|---|
| 默认策略 | 按类型注入(byType) | 按名称注入(byName) |
| 是否支持 @Qualifier | ✅ 支持 | ❌ 不支持 |
| 是否支持 @Primary | ✅ 支持 | ❌ 不支持 |
| 是否可设置 required | ✅ 可选 | ❌ 无此属性 |
| 是否依赖 Spring 框架 | ✅ 是 | ❌ 否(标准注解) |
| 优先查找 | 类型 → 名称 | 名称 → 类型 |
| 使用包 | org.springframework.beans.factory.annotation |
jakarta.annotation |
| 常见错误 | 多个同类型 Bean 报错 | 名称不匹配时报错 |
七、在 Spring Boot 中的推荐实践
| 场景 | 推荐注解 | 理由 |
|---|---|---|
| 纯 Spring 项目 | @Autowired |
Spring 原生,功能更强 |
| 兼容 Jakarta / JavaEE 项目 | @Resource |
标准化,跨框架通用 |
| 有多个 Bean 需区分时 | @Autowired + @Qualifier |
精确控制 |
| 惰性加载或选填依赖 | @Autowired(required = false) |
更灵活 |
💡 Spring 官方文档推荐优先使用
@Autowired,除非需要兼容性或与非 Spring 框架交互。
八、实践建议
- 优先使用
@Autowired(尤其在 Spring Boot 项目中); - 当需要按名称注入时,使用:
java
@Autowired
@Qualifier("beanName")
- 若项目需要兼容 Jakarta EE 或第三方容器,可使用:
java
@Resource(name = "beanName")
- 避免在同一个项目中混用两者,以保持一致性;
- 推荐使用 构造器注入,提高可测试性与代码可维护性。
参考资料