什么是依赖注入以及它在 Spring 中是如何实现的?
Source: Dev.to
介绍
想象一下,你买了一台新电视,每次它坏了都必须自己动手修理,因为所有组件都紧紧焊接在一起。很让人沮丧,对吧?现在再想象每个部件都可以独立更换——维护起来就容易多了。
这正是 依赖注入 (DI) 在 Java 编程 中要解决的问题。
当初学者编写 Java 代码时,类往往会 自行创建其依赖。这会导致应用难以测试、难以修改,并且耦合度高。Spring 通过 依赖注入——其核心概念之一——优雅地解决了这些问题。
在本文中,你将学习 依赖注入是什么、它为何重要,以及 Spring 如何实现它,我们将使用简单的现实类比和干净的 Java 21 示例。阅读完毕后,你将明白为何 DI 被视为现代 Java 开发的基石。
核心概念
什么是依赖注入?
在简单层面,依赖注入意味着给对象它需要的东西,而不是让对象自己创建它。
类比:手机充电器
你的手机不会自己制造充电器。当需要时,你注入充电器到手机中。这允许:
- 不同的充电器
- 轻松更换
- 更好的灵活性
在 Java 中,依赖通常是你的类工作所需的另一个类。
没有依赖注入(紧耦合代码)
public class Car {
private Engine engine = new Engine(); // tightly coupled
}
问题
- 你很难轻易更换引擎
- 难以测试
- 代码僵硬
使用依赖注入(松耦合代码)
public class Car {
private Engine engine;
public Car(Engine engine) {
this.engine = engine;
}
}
现在 Engine 被注入,而不是在内部创建,从而实现灵活性和可测试性。
Spring 如何实现依赖注入
Spring 使用一种称为**控制反转(IoC)**的原则。
- 你定义需要哪些对象。
- Spring 决定如何以及何时创建它们。
- Spring 自动注入依赖。
Spring 支持以下方式的 DI:
- 构造函数注入(推荐)
- Setter 注入
- 字段注入(不推荐)
Spring 中依赖注入的好处
- 松耦合
- 更容易测试(模拟)
- 更好的可维护性
- 更简洁、可读性更高的代码
- 企业级就绪的架构
代码示例(Java 21)
示例 1:构造函数注入(推荐方式)
// Dependency
@Component
public class PaymentService {
public String processPayment() {
return "Payment processed successfully";
}
}
// Dependent class
@Component
public class OrderService {
private final PaymentService paymentService;
// Constructor Injection
public OrderService(PaymentService paymentService) {
this.paymentService = paymentService;
}
public String placeOrder() {
return paymentService.processPayment();
}
}
为什么这样好
- 依赖是显式的
- 易于测试
- 不可变且安全
示例 2:Setter 注入(可选依赖)
@Component
public class NotificationService {
public void notifyUser() {
System.out.println("User notified");
}
}
@Component
public class UserService {
private NotificationService notificationService;
@Autowired
public void setNotificationService(NotificationService notificationService) {
this.notificationService = notificationService;
}
public void registerUser() {
notificationService.notifyUser();
}
}
何时使用
- 当依赖是可选的或可配置时很有用。
最佳实践
- 首选构造函数注入 – 使依赖关系清晰,避免
null问题。 - 避免字段注入 – 隐藏依赖,导致测试困难。
- 面向接口编程,而非实现 – 提高灵活性和可测试性。
- 保持 Bean 专注 – 一个类应只有一个职责。
- 让 Spring 管理对象创建 – 避免对 Spring 管理的 Bean 使用
new。
常见错误要避免
- 将手动对象创建与 Spring DI 混合使用。
- 不必要地过度使用
@Autowired。 - 创建循环依赖。
- 在服务设计中忽视接口。
结论
Spring 中的依赖注入不仅是框架特性——它是一种设计哲学,使 Java 应用程序保持清晰、灵活且易于维护。
通过让 Spring 负责对象创建和依赖装配,你可以减少样板代码,更多地专注于业务逻辑。无论是构建小型 REST API 还是大型企业系统,掌握依赖注入都能立刻提升 Java 编程的质量。