什么是Spring Framework中的依赖注入和控制反转?

Chi*_*lax 103 controls spring dependencies code-injection inversion

"依赖注入"和"控制反转"经常被认为是使用Spring框架开发Web框架的主要优点

如果可能的话,有人可以用一个例子用非常简单的术语解释它是什么吗?

小智 213

  • 由于依赖注入, Spring有助于创建松散耦合的应用程序.
  • 在Spring中,对象定义它们的关联(依赖关系),而不用担心它们将如何获得这些依赖关系.Spring负责为创建对象提供所需的依赖项.

例如:假设我们有一个对象Employee,它依赖于对象Address.我们将定义一个Employee与之对应的bean ,以定义它对对象的依赖性Address.

当Spring尝试创建一个Employee对象时,它会看到它Employee具有依赖关系Address,因此它将首先创建Address对象(依赖对象),然后将其注入Employee对象.

  • 控制反转(IOC)和依赖注入(DI)可互换使用.IOC是通过DI实现的.DI是提供依赖关系的过程,IOC是DI的最终结果.(注意: DI不是实现IOC的唯一方法.还有其他方法.)

  • 通过DI,创建对象的责任从我们的应用程序代码转移到Spring容器; 这种现象称为IOC.

  • 依赖注入可以通过setter注入或构造函数注入来完成.

  • @Boris 没有人说你不能实例化你自己的对象。但答案的唯一目的是展示如何使用 DI 实现相同的目标。您可以通过客户端代码实例化 DI 和对象。这仍将被称为 IOC,至少部分如此。 (3认同)
  • 我不同意。我不认为这是一个明确的解释。为什么你不能在“员工”中实例化“地址”而不是获得一个框架来具体化并注入它?需要一个稍微详细的例子。 (2认同)
  • 鲍里斯。很嫉妒?这是有史以来最好的答案。 (2认同)

Vde*_*deX 28

我将写下我对这两个术语的简单理解:

For quick understanding just read examples*
Run Code Online (Sandbox Code Playgroud)

依赖注入(DI):
依赖注入通常意味着将依赖对象作为参数传递给方法,而不是让方法创建依赖对象.
在实践中它意味着该方法不直接依赖于特定的实现; 任何满足要求的实现都可以作为参数传递.

通过这种对象的实现来定义它们的依赖关系.春天使它可用.
这导致松散耦合的应用程序开发.

Quick Example:EMPLOYEE OBJECT WHEN CREATED,IT WILL AUTOMATICALLY CREATE ADDRESS OBJECT (if address is defines as dependency by Employee object)*.<br>
Run Code Online (Sandbox Code Playgroud)

控制反转(IoC)容器:
这是框架的共同特征,IOC 管理java对象
- 从实例化到通过其BeanFactory进行销毁.
-Iava容器实例化的Java组件称为bean,IoC容器管理bean的范围,生命周期事件以及已配置和编码的任何AOP功能.

QUICK EXAMPLE:Inversion of Control is about getting freedom, more flexibility, and less dependency. When you are using a desktop computer, you are slaved (or say, controlled). You have to sit before a screen and look at it. Using keyboard to type and using mouse to navigate. And a bad written software can slave you even more. If you replaced your desktop with a laptop, then you somewhat inverted control. You can easily take it and move around. So now you can control where you are with your computer, instead of computer controlling it.

通过实现控制反转,软件/对象消费者可以获得对软件/对象的更多控制/选项,而不是受控制或具有更少的选项.

作为设计指南的控制反转具有以下目的:

将某个任务的执行与实现分离开来.
每个模块都可以专注于它的设计目标.
模块不会假设其他系统的功能,而是依赖于合同.
更换模块对其他模块没有任何副作用
我将在这里保持抽象,您可以访问以下链接以了解该主题的详细信息.
一个很好的阅读与例子

详细解释


小智 10

在Spring中,对象是松散耦合的,即每个类彼此独立,因此可以单独测试所有内容.但是在使用这些类时,类可能依赖于需要首先实例化的其他类.

因此,我们告诉Spring,类A依赖于类B.因此,当为类A创建bean(如类)时,它会在类A之前实例化类B,并使用setter或构造函数DI方法在类A中注入它.即,我们在运行时告诉Spring依赖性.这是DI.

因为,我们分配创建对象(bean)的责任,将它们和它们的聚合维护到Spring而不是硬编码,我们称之为控制反转(IOC).


Het*_*chh 9

控制反转——这意味着将创建和实例化 spring bean 的控制权交给 Spring IOC 容器,开发人员所做的唯一工作就是在 spring xml 文件中配置 bean。

依赖注入-

考虑一个班级员工

class Employee { 
   private int id;
   private String name;
   private Address address;

   Employee() {
     id = 10;
     name="name";
     address = new Address();
   }


}
Run Code Online (Sandbox Code Playgroud)

并考虑类地址

class Address {
   private String street;
   private String city;

   Address() {
     street="test";
     city="test1";

  }
}
Run Code Online (Sandbox Code Playgroud)

上面的代码中,只有在Employee类被实例化时才会设置address类的值,这是Address类对Employee类的依赖。spring 使用依赖注入的概念解决了这个问题,提供了两种注入这种依赖的方法。

  1. 二传手注入

Employee 类中的 Setter 方法,它引用了 Address 类

public void setAddress(Address addr) {
    this.address = addr;
}
Run Code Online (Sandbox Code Playgroud)
  1. 构造函数注入

Employee 类中接受地址的构造函数

Employee(Address addr) {
      this.address = addr;
}
Run Code Online (Sandbox Code Playgroud)

通过这种方式,可以使用 setter/constructor 注入独立设置 Address 类值。


Gre*_*mar 8

控制反转(IOC):

IoC是一种描述反转系统中控制流的设计模式,因此执行流程不受中心代码段的控制.这意味着组件应仅依赖于其他组件的抽象,并且不负责处理依赖对象的创建.相反,对象实例在运行时由IoC容器通过依赖注入(DI)提供.

IoC实现了更好的软件设计,有助于重用,松散耦合和轻松测试软件组件.

依赖注入(DI):

DI是一种将依赖项传递给对象构造函数的技术.如果已从容器加载对象,则容器将自动提供其依赖项.这允许您使用依赖项而无需手动创建实例.这减少了耦合,使您可以更好地控制对象实例的生命周期.

点击查看更多


Nee*_*ngh 8

简单来说..

  • IOC(Inversion of Control)是一个概念,意思是:不要用new操作符创建对象,而是让容器为你做这件事。
  • DI(Dependency Injection)是Spring通过以下方式注入框架组件的依赖的方式:
  1. 构造器注入
  2. Setter/Getter 注入
  3. 场注入


小智 6

Spring:Spring是Java平台的"Inversion of Control"容器.

控制反转(IoC):控制反转(IoC)是一种面向对象的编程实践,其中对象耦合在运行时由"汇编器"对象限制,并且在编译时通常不能使用静态分析来识别.

依赖注入(DI):"依赖注入是一种软件设计模式,它允许删除硬编码的依赖关系,并且无论是在运行时还是在编译时都可以更改它们." -wiki.


小智 6

控制反转是软件架构的通用设计原则,有助于创建易于维护的可重用、模块化软件框架。

它是一种设计原则,其中控制流是从通用编写的库或可重用代码“接收”的。

为了更好地理解它,让我们看看我们在早期的编码中是如何使用编码的。在过程/传统语言中,业务逻辑通常控制应用程序的流程并“调用”通用或可重用的代码/函数。例如,在一个简单的控制台应用程序中,我的控制流由我的程序指令控制,其中可能包括对一些通用可重用函数的调用。

print ("Please enter your name:");
scan (&name);
print ("Please enter your DOB:");
scan (&dob);

//More print and scan statements
<Do Something Interesting>

//Call a Library function to find the age (common code)
print Age
Run Code Online (Sandbox Code Playgroud)

相比之下,对于 IoC,框架是“调用”业务逻辑的可重用代码。

例如,在基于 Windows 的系统中,已经可以使用框架来创建 UI 元素,如按钮、菜单、窗口和对话框。当我编写应用程序的业务逻辑时,框架的事件将调用我的业务逻辑代码(当事件被触发时),而不是相反。

虽然框架的代码不知道我的业务逻辑,但它仍然会知道如何调用我的代码。这是使用事件/委托、回调等实现的。这里的流程控制是“反转”。

因此,不是依赖于静态绑定对象的控制流,而是依赖于整个对象图和不同对象之间的关系。

依赖注入是一种设计模式,它实现了 IoC 原则来解决对象的依赖关系。

简单来说,当您尝试编写代码时,您将创建和使用不同的类。一个类(A 类)可以使用其他类(B 类和/或 D 类)。因此,B 类和 D 类是 A 类的依赖项。

一个简单的类比是 Car 类。汽车可能依赖于其他类,如引擎、轮胎等。

依赖注入建议,而不是依赖类(这里的类 Car)创建它的依赖(类引擎和类 Tyre),类应该注入依赖的具体实例。

让我们通过一个更实际的例子来理解。考虑您正在编写自己的文本编辑器。除此之外,您可以拥有一个拼写检查器,为用户提供检查文本中的拼写错误的便利。此类代码的简单实现可以是:

Class TextEditor
{

    //Lot of rocket science to create the Editor goes here

    EnglishSpellChecker objSpellCheck;
    String text;

    public void TextEditor()

    {   

        objSpellCheck = new EnglishSpellChecker();

    }

    public ArrayList <typos> CheckSpellings()
    {

        //return Typos;

    }

}
Run Code Online (Sandbox Code Playgroud)

乍一看,一切都显得红润。用户将编写一些文本。开发人员将捕获文本并调用 CheckSpellings 函数,并将找到他将向用户显示的错字列表。

一切似乎都很好,直到有一天一位用户开始在编辑器中编写法语。

为了提供对更多语言的支持,我们需要有更多的 SpellCheckers。可能是法语、德语、西班牙语等。

在这里,我们创建了一个紧密耦合的代码,其中“English”SpellChecker 与我们的 TextEditor 类紧密耦合,这意味着我们的 TextEditor 类依赖于 EnglishSpellChecker,或者换句话说 EnglishSpellCheker 是 TextEditor 的依赖项。我们需要移除这个依赖。此外,我们的文本编辑器需要一种方法来根据开发人员在运行时的判断来保存任何拼写检查器的具体引用。

因此,正如我们在 DI 的介绍中看到的那样,它建议该类应该注入其依赖项。因此,将所有依赖项注入被调用的类/代码应该是调用代码的责任。所以我们可以将我们的代码重构为

interface ISpellChecker
{

    Arraylist<typos> CheckSpelling(string Text);

}

Class EnglishSpellChecker : ISpellChecker

{

    public override Arraylist<typos> CheckSpelling(string Text)

    {

        //All Magic goes here.

    }

}



Class FrenchSpellChecker : ISpellChecker

{

    public override Arraylist<typos> CheckSpelling(string Text)

    {

        //All Magic goes here.

    }

}
Run Code Online (Sandbox Code Playgroud)

在我们的示例中,TextEditor 类应该接收 ISpellChecker 类型的具体实例。

现在,可以在构造函数、公共属性或方法中注入依赖项。

让我们尝试使用构造函数 DI 更改我们的类。更改后的 TextEditor 类将如下所示:

Class TextEditor

{

    ISpellChecker objSpellChecker;

    string Text;



    public void TextEditor(ISpellChecker objSC)

    {

        objSpellChecker = objSC;

    }



    public ArrayList <typos> CheckSpellings()

    {

        return objSpellChecker.CheckSpelling();

    }

}
Run Code Online (Sandbox Code Playgroud)

这样调用代码在创建文本编辑器时可以将适当的 SpellChecker 类型注入到 TextEditor 的实例中。

你可以在这里阅读完整的文章