@Autowired 和 @Resource 注解区别详解
一、基本介绍
1. @Autowired
- 来源:Spring框架提供的注解
- 包路径:
org.springframework.beans.factory.annotation.Autowired - 默认注入方式:按类型(byType)自动装配
2. @Resource
- 来源:JavaEE标准注解(JSR-250)
- 包路径:
javax.annotation.Resource - 默认注入方式:按名称(byName)自动装配
二、使用方式对比
1. @Autowired 使用示例
// 1. 字段注入(最常用)
@Autowired
private UserDao userDao;
// 2. 构造器注入(推荐用于强制依赖)
private final UserService userService;
@Autowired
public UserController(UserService userService) {
this.userService = userService;
}
// 3. Setter方法注入
private UserRepository userRepository;
@Autowired
public void setUserRepository(UserRepository userRepository) {
this.userRepository = userRepository;
}
// 4. 配合@Qualifier指定具体bean名称
@Autowired
@Qualifier("userServiceImpl")
private UserService userService;
2. @Resource 使用示例
// 1. 按名称注入(默认)
@Resource
private UserDao userDao; // 会查找名为userDao的bean
// 2. 明确指定名称
@Resource(name = "mysqlUserDao")
private UserDao userDao;
// 3. 按类型注入(不推荐,与设计初衷不符)
@Resource(type = UserDao.class)
private UserDao userDao;
三、核心区别详细对比
1. 依赖查找顺序
// @Autowired查找顺序:
// 1. 按类型(byType)查找
// 2. 如果找到多个,按名称(byName)匹配
// 3. 可以通过@Qualifier或@Primary进一步指定
// @Resource查找顺序:
// 1. 如果指定了name属性:只按名称查找
// 2. 如果未指定name属性:
// - 先按字段/属性名查找
// - 再按类型查找
// - 如果找到多个,可以通过@Qualifier指定
2. 具体对比表格
| 特性 | @Autowired | @Resource |
|---|---|---|
| 来源 | Spring框架 | JavaEE标准 |
| 包名 | org.springframework.beans.factory.annotation.Autowired | javax.annotation.Resource |
| 默认注入方式 | byType(按类型) | byName(按名称) |
| 必需性 | 默认必须存在,可设置required=false | 默认必须存在 |
| 指定名称 | 需要配合@Qualifier | 使用name属性 |
| 构造器注入 | 支持 | 不支持 |
| 适用场景 | Spring项目优先推荐 | 需要跨框架或标准化时 |
四、实际应用场景分析
场景1:单一实现类
// 只有一个实现类时,两者都可以
public interface UserService {
void addUser();
}
@Service
public class UserServiceImpl implements UserService {
public void addUser() {
System.out.println("添加用户");
}
}
// 两种注入方式都可以
@Autowired
private UserService userService;
@Resource
private UserService userService;
场景2:多个实现类(需要指定)
// 有多个实现类时需要明确指定
public interface DataSource {
void connect();
}
@Service("mysqlDataSource")
public class MySQLDataSource implements DataSource {
public void connect() {
System.out.println("MySQL连接");
}
}
@Service("oracleDataSource")
public class OracleDataSource implements DataSource {
public void connect() {
System.out.println("Oracle连接");
}
}
// 使用@Autowired需要配合@Qualifier
@Autowired
@Qualifier("mysqlDataSource")
private DataSource dataSource;
// 使用@Resource可以直接指定名称
@Resource(name = "mysqlDataSource")
private DataSource dataSource;
场景3:按名称自动匹配
// 当属性名与bean名称一致时
@Service("userService")
public class UserServiceImpl implements UserService {
// ...
}
// @Autowired:按类型找到多个,然后按名称userService匹配
@Autowired
private UserService userService; // 成功注入userService
// @Resource:直接按名称userService查找
@Resource
private UserService userService; // 成功注入userService
五、异常处理对比
1. @Autowired 异常情况
// 1. 找不到bean时的异常
@Autowired(required = false) // 设置为非必需,找不到时不报错
private OptionalService optionalService;
// 2. 找到多个bean时的异常解决方案
public interface MessageService {
void send();
}
@Service
public class EmailService implements MessageService {
public void send() {
System.out.println("发送邮件");
}
}
@Service
public class SmsService implements MessageService {
public void send() {
System.out.println("发送短信");
}
}
// 解决方案1:使用@Primary
@Service
@Primary // 优先使用
public class EmailService implements MessageService {
// ...
}
// 解决方案2:使用@Qualifier
@Autowired
@Qualifier("smsService")
private MessageService messageService;
// 解决方案3:使用List注入所有实现
@Autowired
private List<MessageService> messageServices;
2. @Resource 异常情况
// 1. 名称不匹配时的处理
@Service("myUserService")
public class UserServiceImpl implements UserService {
// ...
}
// 错误:找不到名为userService的bean
@Resource
private UserService userService;
// 正确:明确指定名称或修改属性名
@Resource(name = "myUserService")
private UserService userService;
// 或者修改属性名匹配
@Resource
private UserService myUserService;
六、最佳实践建议
1. 推荐使用场景
// 场景1:Spring项目优先使用@Autowired
// - 更符合Spring的设计理念
// - 功能更丰富(支持构造器注入等)
@Service
public class OrderService {
private final UserService userService;
// 构造器注入,依赖关系明确
@Autowired
public OrderService(UserService userService) {
this.userService = userService;
}
}
// 场景2:需要标准化或跨框架时使用@Resource
// - 符合JavaEE标准
// - 便于框架迁移
@Component
public class DataProcessor {
@Resource(name = "dataSource")
private DataSource dataSource;
}
2. 实际开发建议
- 强制依赖:使用@Autowired构造器注入,保证依赖不可变
- 可选依赖:使用@Autowired(required = false)
- 明确指定:有多个实现时,明确使用@Qualifier或name属性
- 团队统一:项目中保持注解使用的一致性
七、完整示例代码
// 定义接口
public interface NotificationService {
void notify(String message);
}
// 实现类1
@Service("emailNotification")
public class EmailNotificationService implements NotificationService {
@Override
public void notify(String message) {
System.out.println("邮件通知: " + message);
}
}
// 实现类2
@Service("smsNotification")
public class SmsNotificationService implements NotificationService {
@Override
public void notify(String message) {
System.out.println("短信通知: " + message);
}
}
// 使用类
@Service
public class UserService {
// 方式1:@Autowired + @Qualifier
@Autowired
@Qualifier("emailNotification")
private NotificationService emailService;
// 方式2:@Resource按名称注入
@Resource(name = "smsNotification")
private NotificationService smsService;
// 方式3:注入所有实现
@Autowired
private List<NotificationService> allServices;
public void sendNotifications(String message) {
emailService.notify(message);
smsService.notify(message);
// 使用所有服务
for (NotificationService service : allServices) {
service.notify("批量: " + message);
}
}
}
总结要点
- @Autowired是Spring亲儿子,功能更丰富,推荐在Spring项目中使用
- @Resource是Java标准,适合需要框架兼容性的场景
- 默认行为不同:@Autowired按类型,@Resource按名称
- 明确性优先:有多个实现时一定要明确指定
- 构造器注入是依赖注入的最佳实践,只能用@Autowired
理解这两个注解的区别有助于写出更健壮、更易维护的Spring代码!