Spring依赖注入解决了什么?

时间:2011-12-30 09:27:05

标签: java spring dependency-injection inversion-of-control

请参阅此问题的最佳答案:What exactly is Spring Framework for?

我不知道问题是什么,以及为什么Spring指定在XML文件中使用接口的实现(或使用注释)的解决方案比简单地让一行代码实例化正确的接口更好?

编辑:正如我在其中一篇评论中所写的那样,我真的想要了解它的好处。我想了解为什么Spring很有用。我不主张不使用Spring或试图提供理由而不是,我正在寻找原因并试图理解为什么应该使用它。这篇文章并不是为了鼓励辩论,而是为了直截了当和技术性的答案。我现在选择最短和最具说明性的答案作为正确的答案。我必须说这个问题已经结束我有点意外。

5 个答案:

答案 0 :(得分:5)

如果A类使用B类,则DI负责向B类提供B类。它通常用于测试Spring将提供不同的B类(例如mock)。

当然,您可以自己完成所有这些工作,但如果您让Spring(或任何其他DI框架)为您执行此操作通常会减少工作量。

答案 1 :(得分:1)

  

我不知道问题是什么,

问题基本上是如何在运行时或通过配置文件交换实现。

  

为什么Spring解决方案的put指定了什么实现   在XML文件中使用的接口比简单地使用   代码行实例化正确的接口

最好是因为可以调整XML文件而无需重新编译和重新部署整个应用程序。

这是有关DI的最佳文章之一,你可能想看看它:
http://martinfowler.com/articles/injection.html

答案 2 :(得分:1)

依赖注入解决的主要问题是单元测试。假设您有一个取决于NuclearPlant的DoorOpeningService。要对DoorOpeningService进行单元测试,您需要使用NuclearPlant(这是相当昂贵且难以设置以测试打开的门)。

如果DoorOpeningService的代码如下所示:

public class DoorOpeningServiceImpl implements DoorOpeningService {

    private NuclearPlant plant;

    public DoorOpeningServiceImpl() {
        this.plant = SomeNamingService.lookup("nuclearPlant");
    }

    public void openDoors() {
        int electricity = plant.getSomeElectricity();
        ...
    }
}

DoorOpeningService非常难以进行单元测试。

依赖注入允许将NuclearPlant提供给DoorOpeningService。因此,不需要真正的核电站,你可以给它一个假电厂,它总是提供一些电力,而不需要所有真正的核电站基础设施。因此,DoorOpeningService更容易测试:

public class DoorOpeningServiceImpl implements DoorOpeningService {

    private NuclearPlant plant;

    // The plant is injected by constructor injection
    public DoorOpeningServiceImpl(NuclearPlant plant) {
        this.plant = plant;
    }

    public void openDoors() {
        int electricity = plant.getSomeElectricity();
        ...
    }
}

让框架为您注入依赖项更容易,并且还允许添加其他方面(如果您愿意,可以使用拦截器)。例如,Spring可以代替您的NuclearPlant实现注入此实现的代理,该代理确保每次调用工厂时,事务处于打开状态,或者调用者被授权调用其方法,或者统计信息是聚集在一起帮助诊断应用程序中的慢速部件。

答案 3 :(得分:1)

当您拥有如下代码

时,可以使用依赖注入
Interface i;
if (useA) {
  i = new A();
} else if (useB) {
  i = new B();
} else if (useC) {
  i = new C();
}
i.call();

你有几种不同的Interface,你需要选择在运行程序时使用哪一种,因为在编写程序时你不知道要使用哪一种。这意味着在启动程序时需要找到useAuseBuseC。一种典型的方法是使用检测代码或加载的属性文件,设置这些值。

此外,“实际上 it”部分的人可能很难为例如Web应用程序,主要由从外部调用的代码组成。

依赖注入将此形式化为:

@Injection Interface i;
i.call();

Spring使i自动初始化,因此您不必担心代码中的标志或以标准方式放置工厂的位置。处理A,B,C与实际代码的这种分离已被证明可以创建非常干净的代码。


编辑:当重新审视这个问题时,我明白问题实际上是“为什么在使用依赖注入时可以对getter和setter做同样的事情?”。

在我看来,要实现的重要一点是,依赖注入不能再使用getter和setter,但是唯一可以使用getter和setter的地方就是创建新对象的代码。在Java中是new语句。换句话说,代码需要知道所有细节,而且经常不知道。这就是为什么我们有工厂的工厂 - 作为将决策过程更接近运行时的意思 - 而依赖注入基本上就是这样。工厂框架。但要通知的关键是它允许您将配置部分从正在工作的部分中分离出来并放在其他地方。

答案 4 :(得分:0)

  

我不知道问题是什么,以及为什么Spring指定在XML文件中使用接口的实现(或使用注释)的解决方案比简单地让一行代码实例化正确的接口更好?

首先,无论您的应用是Web应用程序,桌面等,配置看起来都一样(并且可以在同一个地方找到)。这是一个小优势,但我发现它相当方便继承一个项目。

其次,您经常需要对配置进行某种外部化 - 比如将URL更改为外部服务,超时限制等,而无需重建应用程序,这意味着无论如何您最终都会使用配置文件。而恰巧Spring的配置格式非常强大 - 除了能够硬编码东西(比如说“bean fooDaoJpaFooDao的一个实例,使用这里的数据库”),你可以还有refer to Java constants以及系统属性(使用${propertyName}语法),perform JNDI lookupsadd aspect wrappers例如make stuff transactional without coding等等。你可以自己创造的所有这些,但并非没有相当多的工作。

我和任何人一样讨厌XML,但我从来没有发现Spring的XML配置非常麻烦(至少在卸载注释时没有)。