注入依赖的常见方式
注入依赖除了使用 @Autowired ,还有哪些地方可以用到
在 Spring 框架中,除了 @Autowired 注解,还有多种依赖注入方式可供选择,这些方式在代码可维护性、灵活性和规范性上各有优势。以下是具体的替代方案及其应用场景:
一、构造函数注入(Constructor Injection)
实现方式:通过类的构造函数声明依赖项,Spring 自动注入对应的 Bean。
优点:
- 依赖不可变性:强制依赖项在对象创建时必须注入,支持
final字段,避免空指针异常。 - 明确依赖关系:构造函数清晰地展示类所需的依赖,提升可读性和可测试性。
- 避免循环依赖:Spring 在启动时检测循环依赖并抛出异常,而非运行时。
代码示例:
@Service
public class UserService {
private final UserRepository userRepository;
// Spring 4.3+ 可省略 @Autowired
public UserService(UserRepository userRepository) {
this.userRepository = userRepository;
}
}
Lombok 简化:使用 @RequiredArgsConstructor 自动生成构造函数:
@RequiredArgsConstructor
@Service
public class UserService {
private final UserRepository userRepository;
}
二、Setter 方法注入(Setter Injection)
实现方式:通过 Setter 方法注入依赖项,通常配合 @Autowired(或其他注解)使用。
适用场景:
- 可选依赖:依赖项非必需,可通过
@Autowired(required = false)设置。 - 动态更新依赖:允许运行时重新注入不同的实现。
代码示例:
@Service
public class PaymentService {
private PaymentGateway paymentGateway;
@Autowired
public void setPaymentGateway(PaymentGateway paymentGateway) {
this.paymentGateway = paymentGateway;
}
}
三、其他标准注解
1. @Resource(JSR-250)
- 按名称注入:默认根据字段名或
name属性匹配 Bean,类型不匹配时按类型回退。 - 无依赖:属于 Java EE 标准,无需额外依赖。
@Component
public class OrderService {
@Resource(name = "mysqlOrderRepo")
private OrderRepository orderRepository;
}
2. @Inject(JSR-330)
- 与
@Autowired类似:按类型注入,但无required属性。 - 需引入依赖:需添加
javax.inject包。
@Inject
private Logger logger;
四、隐式参数注入(Java Config)
在 @Configuration 类中,通过 @Bean 方法的参数自动注入依赖,无需显式注解:
@Configuration
public class AppConfig {
@Bean
public DataSource dataSource(Environment env) {
// 参数 env 自动注入
return new HikariDataSource(...);
}
}
五、@Qualifier 精确注入
解决歧义:当存在多个同类型 Bean 时,通过名称或自定义限定符明确指定目标 Bean:
@Service
public class ReportService {
private final DataSource primaryDataSource;
public ReportService(@Qualifier("primaryDataSource") DataSource dataSource) {
this.primaryDataSource = dataSource;
}
}
六、模块化配置与自动装配
Spring Boot Starter:通过 META-INF/spring.factories 或 @AutoConfiguration 自动注册 Bean,开发者仅需引入依赖即可使用。例如引入 spring-boot-starter-data-jpa 后,DataSource 和 JpaTemplate 自动配置。
对比总结
| 方式 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|
| 构造函数注入 | 依赖不可变,明确性强 | 参数较多时代码冗长 | 必需依赖,推荐默认使用 |
| Setter 注入 | 支持可选依赖,灵活性高 | 依赖可变性可能引发问题 | 可选或需动态更新的依赖 |
@Resource |
按名称注入,标准化 | 灵活性低于 @Autowired |
需精确匹配 Bean 名称时 |
@Inject |
标准化,跨框架兼容性好 | 无 required 属性 |
需要与 Guice 等框架兼容时 |
| 隐式参数注入 | 配置简洁,无需注解 | 仅适用于 @Configuration 类 |
手动配置复杂 Bean 时 |
最佳实践建议
- 优先构造函数注入:强制依赖项声明,提升代码安全性和可维护性。
- 慎用字段注入:仅在原型代码或遗留系统中使用,避免隐藏依赖和测试困难。
- 结合 Lombok:通过
@RequiredArgsConstructor减少样板代码,保持代码简洁。 - 利用自动装配:通过 Starter 减少手动配置,遵循 Spring Boot 的约定优于配置原则。
通过合理选择依赖注入方式,可以显著提升代码质量,降低维护成本。

浙公网安备 33010602011771号