Spring 依赖注入

每个基于 Java 的应用程序都有一些对象,它们协同工作以呈现最终用户所看到的工作应用程序。 在编写复杂的 Java 应用程序时,应用程序类应尽可能独立于其他 Java 类,以增加重用这些类的可能性,并在单元测试时独立于其他类对其进行测试。 依赖注入(或有时称为连接)有助于将这些类粘合在一起,同时保持它们独立。

假设您有一个具有文本编辑器组件的应用程序,并且您想要提供拼写检查。 您的标准代码看起来像这样 −


public class TextEditor {
   private SpellChecker spellChecker;
   
   public TextEditor() {
      spellChecker = new SpellChecker();
   }
}

我们在这里所做的是,在 TextEditor 和 SpellChecker 之间创建依赖关系。 在控制反转的情况下,我们会做这样的事情 −


public class TextEditor {
   private SpellChecker spellChecker;
   
   public TextEditor(SpellChecker spellChecker) {
      this.spellChecker = spellChecker;
   }
}

在这里,TextEditor 不应该担心 SpellChecker 的实现。 SpellChecker 将独立实现,并在 TextEditor 实例化时提供给 TextEditor。 整个过程由 Spring Framework 控制。

在这里,我们从 TextEditor 中移除了全部控制权并将其保存在其他地方(即 XML 配置文件),并且依赖项(即 SpellChecker 类)通过 Class Constructor 注入到 TextEditor 类中。因此,依赖注入 (DI) 已经"反转"了控制流,因为您已经有效地将依赖委托给了某个外部系统。

注入依赖项的第二种方法是通过 TextEditor 类的 Setter 方法,我们将在其中创建一个 SpellChecker 实例。 此实例将用于调用 setter 方法来初始化 TextEditor 的属性。

因此,DI 存在两个主要变体,以下两个子章节将通过示例介绍它们 −

序号 依赖注入类型 & 描述
1

基于构造函数的依赖注入

当容器调用具有多个参数的类构造函数时,就完成了基于构造函数的 DI,每个参数代表对另一个类的依赖。

2

基于 Setter 的依赖注入

基于 Setter 的 DI 是通过容器在调用无参数构造函数或无参数静态工厂方法来实例化 bean 后调用 bean 上的 setter 方法来完成的。

您可以混合使用基于构造函数的 DI 和基于 Setter 的 DI,但根据经验,对强制依赖项使用构造函数参数,对可选依赖项使用 setter 是一个很好的经验法则。

使用 DI 原则,代码更干净,当对象具有依赖关系时,解耦更有效。 该对象不查找其依赖项,也不知道依赖项的位置或类,而是由 Spring 框架处理所有内容。


基于构造函数与基于 Setter 的依赖注入。

基于构造函数和基于 setter 的依赖注入之间几乎没有值得注意的区别。

  • 粒度控制 − 如果构造函数接受多个值,我们需要在 bean 配置期间传递所有值,而对于 setter,我们可以在特定的 setter 方法中传递值,并且可以不配置其他 setter。

  • Setter 重写构造函数 − 如果同时使用构造函数和基于 setter 的注入,则优先使用基于 setter 的注入。

  • 灵活性 − Setter 方法不会像构造函数那样创建新的 bean 实例,并且它们的值也可以更改。