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

时间:2012-02-22 21:16:12

标签: spring dependencies controls code-injection inversion

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

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

11 个答案:

答案 0 :(得分:204)

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

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

当Spring尝试创建Employee对象时,它会看到Employee依赖于Address,因此它将首先创建Address对象(依赖对象) )然后将其注入Employee对象。

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

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

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

答案 1 :(得分:24)

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

For quick understanding just read examples*

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

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

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

控制反转(IoC)容器:
这是框架的共同特征, IOC 管理java对象
- 从实例化到通过BeanFactory进行销毁。
-IoC容器实例化的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

通过实施控制反转,软件/对象消费者可以获得更多关于软件/对象的控制/选项,而不是被控制或拥有更少的选项。

作为设计指南的控制反转有以下用途:

将某项任务的执行与实施脱钩 每个模块都可以专注于它的设计目标 模块不会假设其他系统的功能,而是依赖于他们的合同 更换模块对其他模块没有任何副作用。我将在这里保留摘要。您可以访问以下链接以了解该主题的详细信息。
A good read with example

Detailed explanation

答案 2 :(得分:7)

控制倒置(IOC):

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

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

依赖注入(DI):

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

click to view more

答案 3 :(得分:6)

Spring:Spring是Java平台的“Inversion of Control”容器。

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

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

答案 4 :(得分:6)

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

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

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

答案 5 :(得分:4)

控制反转- 这意味着将创建和实例化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();
   }


}

并考虑地址类

class Address {
   private String street;
   private String city;

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

  }
}

在上面的代码中,仅在实例化Employee类时设置地址类值,这是Address类对Employee类的依赖。 spring使用“依赖注入”概念解决了这个问题,它提供了两种方法来注入此依赖。

  1. 固定注射

Employee类中的设置方法,该方法引用Address类

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

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

Employee(Address addr) {
      this.address = addr;
}

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

答案 6 :(得分:3)

控制反转是软件体系结构的通用设计原理,可帮助创建易于维护的可重用模块化软件框架。

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

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

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

与IoC相反,框架是可重用的代码,用于“调用”业务逻辑。

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

尽管,框架的代码不了解我的业务逻辑,但仍会知道如何调用我的代码。这是通过事件/代理,回调等实现的。这里的流控制是“反转的”。

因此,与其依赖于静态绑定对象的控制流,不如依赖于整体对象图和不同对象之间的关系。

依赖注入是一种实现IoC原理以解决对象依赖的设计模式。

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

一个简单的类比将是Car类。汽车可能取决于其他类别,例如发动机,轮胎等。

依赖注入建议,与其创建依赖关系(类引擎和轮胎类)的依赖类(此处为Class Car),不如使用依赖的具体实例来注入类。

让我们用一个更实际的例子来理解。考虑您正在编写自己的TextEditor。除其他外,您可以使用拼写检查器,该工具为用户提供了一种检查其文字输入错误的工具。这样的代码的简单实现可以是:

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;

    }

}

乍一看,一切看起来都很乐观。用户将写一些文本。开发人员将捕获文本并调用CheckSpellings函数,并找到他将显示给用户的Typos列表。

一切正常,直到一天下来,一个用户开始在编辑器中编写法语。

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

在这里,我们创建了一个紧密耦合的代码,其中“ 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.

    }

}

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

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

让我们尝试使用构造函数DI来更改我们的类。更改后的TextEditor类将类似于:

Class TextEditor

{

    ISpellChecker objSpellChecker;

    string Text;



    public void TextEditor(ISpellChecker objSC)

    {

        objSpellChecker = objSC;

    }



    public ArrayList <typos> CheckSpellings()

    {

        return objSpellChecker.CheckSpelling();

    }

}

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

您可以阅读完整的文章here

答案 7 :(得分:2)

IOC代表控制权的反转,它是一个更高层次的概念,它表示我们将对象创建的控制权从调用者转换为被调用者。

在没有控制反转的情况下,您将负责对象的创建。在控制反转的情况下,框架负责创建类的实例。

依赖注入是我们可以实现控制反转的方法。为了使控件不受框架或作业的影响,我们声明了依赖项,然后IOC容器将这些依赖项注入到类中(即框架为我们创建了一个实例并将其提供给我们的类)。

现在这有什么好处?

首先,所有类及其生命周期将由Spring管理。 Spring完全管理从创建到破坏的整个过程。

第二,您将减少类之间的耦合。一个类没有与另一个类的实现紧密结合。如果实现发生更改,或者您想更改注入接口的实现,则可以轻松地做到这一点,而无需手动更改代码库中的所有实例。

第三,班级之间的凝聚力增强。高凝聚力意味着将彼此关联的类保持在一起。因为我们在其他类中注入接口,所以很明显哪些类对于调用类是必需的。

第四,可测试性增强。因为我们在构造函数中使用接口,所以我们可以轻松地用模拟实现换出实现

第五,使用JDK动态代理来代理对象。 JDK动态代理要求使用正确的接口,因为我们正在注入这些接口。然后,该代理可以用于Spring AOP,事务处理,Spring数据,Spring安全性等等。

答案 8 :(得分:1)

在Employee中获取地址实例的传统方法是创建一个Address类的新实例.Spring创建所有依赖对象,因此我们不必担心对象。

所以在Spring中我们只依赖于弹簧容器,它为我们提供了依赖对象。

答案 9 :(得分:1)

简单来说..

  • IOC(控制反转)的含义是:代替使用new运算符创建对象,请让容器为您完成操作。
  • DI(依赖关系注入)是通过以下几种方式注入框架组件的依赖关系的方法:
  1. 喷油器
  2. Setter / Getter注入
  3. 现场注入

答案 10 :(得分:0)

IOC是一种让其他人为您创建对象的技术。 如果是春季,还有其他人是IOC容器。

依赖注入是一种技术,其中一个对象提供了另一个对象的依赖。