Spring 简明教程
Spring - Dependency Injection
每个基于 Java 的应用程序都有一些对象可以协同工作,以展示最终用户所看到的工作应用程序。在编写复杂的 Java 应用程序时,应用程序类应尽可能独立于其他 Java 类,以增加重用这些类并使其独立于其他类进行单元测试的可能性。依赖注入(或有时称为连接)有助于将这些类粘合在一起,同时又保持它们独立性。
Every Java-based application has a few objects that work together to present what the end-user sees as a working application. When writing a complex Java application, application classes should be as independent as possible of other Java classes to increase the possibility to reuse these classes and to test them independently of other classes while unit testing. Dependency Injection (or sometime called wiring) helps in gluing these classes together and at the same time keeping them independent.
考虑您有一个包含文本编辑器组件的应用程序,并且您希望提供拼写检查。您的标准代码将如下所示 −
Consider you have an application which has a text editor component and you want to provide a spell check. Your standard code would look something like this −
public class TextEditor {
private SpellChecker spellChecker;
public TextEditor() {
spellChecker = new SpellChecker();
}
}
我们在此处所做的是创建 TextEditor 和 SpellChecker 之间的依赖关系。在控制反转场景中,我们改为执行类似以下操作 −
What we’ve done here is, create a dependency between the TextEditor and the SpellChecker. In an inversion of control scenario, we would instead do something like this −
public class TextEditor {
private SpellChecker spellChecker;
public TextEditor(SpellChecker spellChecker) {
this.spellChecker = spellChecker;
}
}
在这里,TextEditor 不应该担心 SpellChecker 实现。SpellChecker 将被独立实现,并在 TextEditor 实例化时提供给 TextEditor。此整个过程由 Spring 框架控制。
Here, the TextEditor should not worry about SpellChecker implementation. The SpellChecker will be implemented independently and will be provided to the TextEditor at the time of TextEditor instantiation. This entire procedure is controlled by the Spring Framework.
在此,我们从 TextEditor 中删除了全部控制权,并将其保存在其他地方(即 XML 配置文件),并且依赖项(即类 SpellChecker)正在通过 Class Constructor 注入到类 TextEditor 中。因此,依赖注入(DI)已经“反转”了控制流,因为您实际上已经将依赖委托给某个外部系统。
Here, we have removed total control from the TextEditor and kept it somewhere else (i.e. XML configuration file) and the dependency (i.e. class SpellChecker) is being injected into the class TextEditor through a Class Constructor. Thus the flow of control has been "inverted" by Dependency Injection (DI) because you have effectively delegated dependances to some external system.
注入依赖关系的第二种方法是通过 TextEditor 类的 Setter Methods ,我们将在其中创建 SpellChecker 实例。此实例将用于调用 setter 方法来初始化 TextEditor 的属性。
The second method of injecting dependency is through Setter Methods of the TextEditor class where we will create a SpellChecker instance. This instance will be used to call setter methods to initialize TextEditor’s properties.
因此,DI 以两种主要形式存在,以下两个小章节将用示例介绍它们 −
Thus, DI exists in two major variants and the following two sub-chapters will cover both of them with examples −
Sr.No. |
Dependency Injection Type & Description |
1 |
Constructor-based dependency injectionConstructor-based DI is accomplished when the container invokes a class constructor with a number of arguments, each representing a dependency on the other class. |
2 |
Setter-based dependency injectionSetter-based DI is accomplished by the container calling setter methods on your beans after invoking a no-argument constructor or no-argument static factory method to instantiate your bean. |
您可以混合使用基于构造函数的 DI 和基于 setter 的 DI,但一个好经验法则是对强制依赖关系使用构造函数参数,对可选依赖关系使用 setter。
You can mix both, Constructor-based and Setter-based DI but it is a good rule of thumb to use constructor arguments for mandatory dependencies and setters for optional dependencies.
使用 DI 原则的代码更简洁,当对象获得其依赖项时,解耦将更加有效。对象不会查找其依赖项,并且不知道依赖项的位置或类,而是 Spring 框架负责所有操作。
The code is cleaner with the DI principle and decoupling is more effective when objects are provided with their dependencies. The object does not look up its dependencies and does not know the location or class of the dependencies, rather everything is taken care by the Spring Framework.