Spring依赖注入注解详解:@Autowired、@Resource、@Inject
一、注解概览
注解 | 所属标准 | 装配方式 | 是否支持required | 包路径 |
---|---|---|---|---|
@Autowired | Spring原生 | 类型优先,支持名称 | 支持 | org.springframework.beans.factory.annotation |
@Resource | JSR-250 | 名称优先,支持类型 | 不支持 | javax.annotation |
@Inject | JSR-330 | 类型优先,支持名称 | 不支持 | javax.inject |
二、核心原理剖析
1. @Autowired
- 处理器:AutowiredAnnotationBeanPostProcessor
- 装配流程 :
- 根据类型查找候选Bean
- 使用@Qualifier或限定符缩小范围
- 按名称匹配(当找不到唯一类型时)
- 处理@Primary标注的Bean
- 处理泛型依赖
2. @Resource
- 处理器:CommonAnnotationBeanPostProcessor
- 解析策略 :
- 未指定name时:按字段/方法名称查找
- 指定name时:直接按名称查找,失败后回退到类型匹配
3. @Inject
- 依赖:需引入javax.inject包
- 实现机制 :
- 类似@Autowired但无required属性
- 配合@Named实现名称注入
三、使用场景与案例
1. 基础注入示例
java
// @Autowired构造器注入(推荐)
@Service
public class OrderService {
private final OrderRepository repository;
@Autowired
public OrderService(OrderRepository repository) {
this.repository = repository;
}
}
// @Resource字段注入
@Repository
public class UserDao {
@Resource(name = "secondaryDataSource")
private DataSource dataSource;
}
// @Inject方法注入
@Component
public class PaymentProcessor {
private GatewayService gateway;
@Inject
public void setGateway(@Named("wechat") GatewayService gateway) {
this.gateway = gateway;
}
}
2. 特殊场景处理
多实现类选择:
java
@Configuration
public class AppConfig {
@Bean
@Primary
public Cache redisCache() {
return new RedisCache();
}
@Bean
@Qualifier("local")
public Cache localCache() {
return new LocalCache();
}
}
@Service
public class CacheService {
@Autowired // 注入RedisCache
private Cache cache;
@Autowired
@Qualifier("local") // 明确指定
private Cache localCache;
}
四、避坑指南
1. 常见异常及解决方案
- NoSuchBeanDefinitionException
- 检查组件扫描配置
- 确认Bean是否被正确加载(@Component/@Bean)
- NoUniqueBeanDefinitionException
- 使用@Qualifier限定
- 设置@Primary Bean
- 显式指定Bean名称
2. 循环依赖问题
- 症状:BeanCurrentlyInCreationException
- 解决方案 :
- 使用setter注入替代构造器注入
- @Lazy延迟初始化
- 重构代码结构
3. 作用域陷阱
java
@Autowired
private RequestScopedBean bean; // 可能注入代理对象
五、最佳实践
-
注入方式优先级
- 构造器注入 > Setter注入 > 字段注入
- 强制依赖使用构造器注入,可选依赖使用Setter
-
注解选择策略
- Spring项目首选@Autowired
- 需要JSR标准支持时用@Resource/@Inject
- 跨容器应用考虑@Resource
-
命名规范
- 保持Bean名称一致性:
java@Service("userService") // 显式命名 public class UserServiceImpl implements UserService {} @Resource(name = "userService") // 准确匹配 private UserService service;
-
测试友好性
- 使用构造器注入方便Mock测试
java@Test void testService() { UserRepository mockRepo = Mockito.mock(UserRepository.class); UserService service = new UserService(mockRepo); // 测试逻辑 }
六、总结对比
维度 | @Autowired | @Resource | @Inject |
---|---|---|---|
标准性 | Spring特有 | JSR-250 | JSR-330 |
灵活性 | 高(支持required) | 中 | 中 |
装配策略 | 类型优先 | 名称优先 | 类型优先 |
依赖 | 无 | 无 | 需javax.inject |
适用场景 | 纯Spring项目 | 跨容器应用 | 标准Java项目 |
最终建议:单一框架项目优先使用@Autowired,需要标准化时根据场景选择@Resource/@Inject。保持代码的注入方式统一,合理使用限定符,避免过度依赖自动装配。
通过本文的解析,读者可以全面掌握Spring核心依赖注入注解的使用技巧,避免常见的配置陷阱,构建更健壮的应用程序。实际开发中应根据项目需求和团队规范灵活选择合适的注入策略。