Java中的依赖注入:面向初学者的完整指南

面向初学者的在线Python训练器

轻松学习Python,无需理论负担。在浏览器中直接解决带自动检查的实践任务,无需安装任何东西。

开始课程

什么是Java中的依赖注入,为什么需要它?



想象一下你在盖房子。你需要砖块、水泥和工具。如果你每次都自己去挖粘土、烧砖、煮水泥,那么建造过程将耗费无尽的时间。更简单的方式是,材料已经准备好并运送到工地。这正是依赖注入(DI)在Java中的工作方式——它是一种设计模式,对象从外部获取现成的依赖,而不是自己创建它们。



简单来说:依赖注入就是一个对象将所需的所有依赖传递给另一个对象。类不再自己创建依赖,而是通过构造函数、setter方法或接口来获取它们。



为什么依赖注入如此重要?



  • 降低代码耦合度:类不再紧密依赖于具体的实现。
  • 简化测试:在单元测试中,你可以轻松地将真实对象替换为模拟对象(mock对象)。
  • 提高可复用性:同一个类可以在不同的上下文中使用。
  • 改善可读性:代码变得更清晰,依赖关系也变得明确。


没有依赖注入的问题:反模式“紧耦合”



让我们看一个典型的没有使用DI的代码示例。假设我们有一个发送邮件的EmailService类,以及一个使用EmailService的NotificationService类。



// 没有DI的类——糟糕的例子public class EmailService {    public void sendEmail(String message) {        System.out.println("发送邮件: " + message);    }}

public class NotificationService { private EmailService emailService;

public NotificationService() { // 问题:在类内部直接创建依赖 this.emailService = new EmailService(); }

public void sendNotification(String message) { emailService.sendEmail(message); }}


这段代码的问题在哪里?



  • 紧耦合:NotificationService与EmailService紧密绑定。如果你想发送短信而不是邮件,就必须重写类。
  • 测试困难:你无法将EmailService替换为测试桩(mock)。
  • 违反单一职责原则:NotificationService类不仅负责通知,还负责创建发送服务。


依赖注入如何工作:三种注入方式



在Java中,有三种主要方式来实现依赖注入。让我们通过代码示例逐一介绍。



1. 构造函数注入



这是最常见且推荐的方式。依赖通过构造函数参数传递。



// 接口以实现灵活性public interface MessageService {    void sendMessage(String message);}

// 邮件实现public class EmailService implements MessageService { @Override public void sendMessage(String message) { System.out.println("邮件已发送: " + message); }}

// 短信实现public class SmsService implements MessageService { @Override public void sendMessage(String message) { System.out.println("短信已发送: " + message); }}

// 通过构造函数实现DI的类public class NotificationService { private final MessageService messageService;

// 通过构造函数注入依赖 public NotificationService(MessageService messageService) { this.messageService = messageSe

博客

书籍推荐