依赖注入(Dependency Injection)的三种核心方式详解
核心逻辑:通过类的构造函数传递依赖对象,强制在对象创建时完成依赖注入。
Spring实现:
@Service
public class OrderService {
private final PaymentService paymentService;
// 构造器声明依赖
public OrderService(PaymentService paymentService) {
this.paymentService = paymentService;
}
}
或在XML中配置:
<bean id="orderService" class="com.example.OrderService">
<constructor-arg ref="paymentService"/>
</bean>
核心逻辑:通过Setter方法动态设置依赖,允许对象在创建后修改依赖。
Spring实现:
public class UserService {
private UserRepository userRepository;
// Setter方法声明依赖
@Autowired
public void setUserRepository(UserRepository userRepository) {
this.userRepository = userRepository;
}
}
XML配置:
<bean id="userService" class="com.example.UserService">
<property name="userRepository" ref="jdbcUserRepository"/>
</bean>
@Service
public class ProductService {
@Autowired
private InventoryService inventoryService;
}
维度 | 构造器注入 | Setter注入 | 字段注入 |
---|---|---|---|
不可变性 | ✅ 支持final字段 | ❌ 依赖可变 | ❌ 依赖可变 |
代码可读性 | 明确声明所有依赖 | 显式Setter方法 | 依赖关系隐蔽 |
循环依赖处理 | 不支持(默认) | 支持 | 支持 |
单元测试 | 易通过参数传递Mock | 需调用Setter | 需反射或容器 |
Spring官方推荐 | 优先使用(尤其必选依赖) | 可选依赖场景 | 谨慎使用(避免过度依赖) |
public class NotificationService {
private final EmailSender emailSender; // 必选
private SMSSender smsSender; // 可选
public NotificationService(EmailSender emailSender) {
this.emailSender = emailSender;
}
@Autowired(required = false)
public void setSmsSender(SMSSender smsSender) {
this.smsSender = smsSender;
}
}
@Bean
public OrderService orderService(PaymentService paymentService) {
return new OrderService(paymentService);
}
@Service
@RequiredArgsConstructor
public class AuthService {
private final UserRepository userRepository;
private final PasswordEncoder passwordEncoder;
}
总结:依赖注入是Spring实现控制反转的核心手段,三种方式各有适用场景。构造器注入因其安全性和明确性成为现代Spring应用的首选方案,Setter注入在动态配置场景仍有价值,而字段注入应作为辅助手段有限使用。理解其差异与适用边界,有助于构建更健壮、可维护的应用程序架构。