Spring依赖注入方式
依赖注入方式
Spring框架主要支持以下三种依赖注入方式:构造器注入、Setter方法注入和字段注入。每种方式有各自的特点和适用场景。
构造器注入
通过类的构造器实现依赖注入,Spring容器在创建Bean实例时传入依赖对象。
特点
- 强依赖性:适合必须依赖的场景,避免对象状态不完整。
- 不可变性:注入后依赖不可变,适合final字段。
- 线程安全:对象创建后依赖关系不再变化。
优点
- 明确依赖关系,便于单元测试。
- 避免循环依赖问题。
- 符合不可变对象设计原则。
缺点
- 参数较多时代码冗长。
示例
@Service
public class UserService {private final UserRepository userRepository;@Autowiredpublic UserService(UserRepository userRepository) {this.userRepository = userRepository;}
}
Setter方法注入
通过setter方法实现依赖注入,Spring容器调用setter方法传入依赖对象。
特点
- 可选依赖:适合非必须依赖的场景。
- 可重新注入:允许运行时重新配置依赖。
优点
- 灵活性高,便于动态更换依赖。
- 代码可读性好,参数多时更清晰。
缺点
- 对象状态可能在生命周期中变化。
- 可能隐藏依赖关系,导致NPE风险。
示例
@Service
public class OrderService {private PaymentService paymentService;@Autowiredpublic void setPaymentService(PaymentService paymentService) {this.paymentService = paymentService;}
}
字段注入
通过反射直接注入字段依赖,使用@Autowired注解标注字段。
特点
- 简洁性:代码量最少,直接标注字段。
- 隐蔽性:依赖关系不明显。
优点
- 编写快速,适合快速原型开发。
- 减少样板代码。
缺点
- 难以进行单元测试(需要反射或Spring容器)。
- 违反单一职责原则,容易过度注入。
- 可能隐藏设计问题。
示例
@Service
public class ProductService {@Autowiredprivate InventoryService inventoryService;
}
选择建议
构造器注入适用场景
- 强依赖的组件(如数据库访问层)
- 需要不可变状态的场景
- 希望明确显示所有依赖
- Spring 4.3+版本中单构造器可省略@Autowired
Setter注入适用场景
- 可选依赖配置
- 需要动态重新配置的bean
- 遗留代码改造场景
字段注入适用场景
- 快速原型开发
- 简单的控制器类
- 内部工具类(非公共API)
最佳实践组合
- 核心业务逻辑优先使用构造器注入
- 可选基础设施组件使用setter注入
- 控制器/简单bean可酌情使用字段注入
- 避免混合使用多种注入方式
现代Spring推荐
Spring官方自4.x版本开始推荐构造器注入作为主要方式:
@Service
public class ModernService {private final DependencyA a;private final DependencyB b;// Spring4.3+ 单构造器可自动装配public ModernService(DependencyA a, DependencyB b) {this.a = a;this.b = b;}
}
对于集合类型注入,Spring支持所有三种方式:
// 构造器方式
public class CollectionInjection {private final List<Validator> validators;public CollectionInjection(List<Validator> validators) {this.validators = validators;}
}// Setter方式
public void setValidators(List<Validator> validators) {this.validators = validators;
}// 字段方式
@Autowired
private List<Validator> validators;
特殊注入场景
Optional依赖
Spring 5.0+支持Optional包装:
public class OptionalService {private final Optional<SecondaryService> service;public OptionalService(Optional<SecondaryService> service) {this.service = service;}
}
懒加载注入
结合@Lazy注解实现延迟初始化:
public class LazyService {@Lazy@Autowiredprivate HeavyResource resource;
}
限定符注入
使用@Qualifier解决歧义:
public class QualifierExample {@Autowired@Qualifier("mainDataSource")private DataSource dataSource;
}