注入依赖除了使用 @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 的约定优于配置原则。
通过合理选择依赖注入方式,可以显著提升代码质量,降低维护成本。