Java中的依赖注入(Dependency Injection):完整指南

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

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

开始课程

引言:为什么依赖注入是Java开发者的必备技能

每个Java开发者迟早都会面临代码耦合度紧的问题。当一个类直接创建其他类的实例时,系统会变得脆弱、难以测试和修改。解决这个问题的方案就是依赖注入(DI)。这是现代开发的关键原则之一,也是Spring和Jakarta EE等框架的基础。

在本文中,我们将深入解析什么是DI,它如何与IoC(控制反转)区分,通过清晰的代码示例展示Java中三种主要的依赖注入方式,并探讨为什么这种模式对于创建可维护的应用程序是必要的。



什么是依赖注入和控制反转?

在进入代码之前,理解两个基本概念很重要。

控制反转(IoC)是一个通用原则,程序的控制流被转移到外部框架或容器。代码不再自行决定何时创建对象和调用方法,而是由外部系统来处理。

依赖注入是IoC原则的一种具体实现。它是一种模式,对象从外部接收其依赖项(它所依赖的其他对象),而不是自己创建它们。

简单来说,不是由Car类自己创建引擎(new Engine()),而是通过构造函数或setter接收一个现成的引擎。这使得Car类独立于具体的Engine实现。



Java中依赖注入的三种方式

在Java中,有三种主要方法来实现DI。让我们以一个简单的通知系统为例,逐一看看它们。



1. 构造函数注入

这是最推荐且最安全的方法。依赖项通过类的构造函数传递。这保证了对象永远不会在无效状态下被创建,因为所有必需的依赖项都是强制性的。

// 通知服务接口public interface MessageService {    void sendMessage(String message, String recipient);}

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

// 使用通知服务的类public class NotificationSender { private final MessageService service; // 依赖项

// 构造函数注入 public NotificationSender(MessageService service) { this.service = service; }

public void notifyUser(String user, String msg) { this.service.sendMessage(msg, user); }}

// 使用示例public class Main { public static void main(String[] args) { MessageService emailService = new EmailService(); NotificationSender sender = new NotificationSender(emailService); // DI sender.notifyUser("user@example.com", "你好!"); }}


2. Setter注入

这种方法在依赖项不是必需的,或者可以在对象创建后更改时使用。依赖项通过公共的setter方法传递。

public class NotificationSenderWithSetter {    private MessageService service; // 依赖项非必需

// 用于注入的setter public void setMessageService(MessageService service) { this.service = service; }

public void notifyUser(String user, String msg) { if (service != null) { this.service.sendMessage(msg, user); } else { System.out.println("未配置服务!"); } }}

// 使用示例

博客

书籍推荐