@Autowired 和 @Resource 注解区别详解

117 阅读4分钟

@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.Autowiredjavax.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. 实际开发建议

  1. 强制依赖​:使用@Autowired构造器注入,保证依赖不可变
  2. 可选依赖​:使用@Autowired(required = false)
  3. 明确指定​:有多个实现时,明确使用@Qualifier或name属性
  4. 团队统一​:项目中保持注解使用的一致性

七、完整示例代码

// 定义接口
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);
        }
    }
}

总结要点

  1. ​@Autowired是Spring亲儿子,功能更丰富,推荐在Spring项目中使用
  2. ​@Resource是Java标准,适合需要框架兼容性的场景
  3. 默认行为不同​:@Autowired按类型,@Resource按名称
  4. 明确性优先​:有多个实现时一定要明确指定
  5. 构造器注入是依赖注入的最佳实践,只能用@Autowired

理解这两个注解的区别有助于写出更健壮、更易维护的Spring代码!