什么是依赖注入以及它在 Spring 中是如何实现的?

发布: (2025年12月19日 GMT+8 11:16)
5 min read
原文: Dev.to

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 编程的质量。

Back to Blog

相关文章

阅读更多 »