依赖项注入容器的好处是什么?


104

我了解依赖注入本身的好处。让我们以Spring为例。我还了解其他Spring功能(如AOP,不同类型的助手等)的好处。我只是想知道XML配置的好处是什么,例如:

<bean id="Mary" class="foo.bar.Female">
  <property name="age" value="23"/>
</bean>
<bean id="John" class="foo.bar.Male">
  <property name="girlfriend" ref="Mary"/>
</bean>

与普通的旧Java代码相比,例如:

Female mary = new Female();
mary.setAge(23);
Male john = new Male();
john.setGirlfriend(mary);

它更容易调试,检查编译时间,并且仅懂Java的任何人都可以理解。那么,依赖注入框架的主要目的是什么?(或一段显示其优点的代码。)


更新:
如果

IService myService;// ...
public void doSomething() {  
  myService.fetchData();
}

如果存在多个,IoC框架如何猜测要注入的myService的哪种实现?如果给定接口只有一个实现,而我让IoC容器自动决定使用它,则在出现第二个实现后,它将被破坏。并且,如果有意仅使用一种可能的接口实现,则无需注入该接口。

看到IoC的一小部分配置显示出它的好处,这将真的很有趣。我已经使用Spring一段时间了,我无法提供这样的示例。而且我可以显示单行代码,这些代码演示了休眠,dwr和其他我使用的框架的好处。


更新2:
我意识到IoC配置可以更改而无需重新编译。真的是个好主意吗?我可以理解,当有人想更改数据库凭据而无需重新编译时-他可能不是开发人员。在您的实践中,除开发人员外,其他人多久更改一次IoC配置?我认为对于开发人员而言,无需重新编译该特定类,而无需更改配置。对于非开发人员,您可能希望使他的生活更轻松,并提供一些更简单的配置文件。


更新3:

接口之间的映射及其具体实现的外部配置

使它具有延展性有什么好处?您不必将所有代码都放在外部,但可以肯定地将代码放在ClassName.java.txt文件中,可以即时读取和手动进行编译-哇,您避免了重新编译。为什么要避免编译?

节省编码时间,因为您以声明方式而不是在过程代码中提供映射

我知道有时声明式方法可以节省时间。例如,我仅声明一次bean属性与DB列之间的映射,并且hibernate在加载,保存,构建基于HSQL的SQL等方式时使用此映射。这就是声明性方法的工作原理。在Spring的情况下(在我的示例中),声明具有更多的行,并且与相应的代码具有相同的表现力。如果有这样的声明比代码短的例子-我希望看到它。

控制反转的原理使单元测试变得容易,因为您可以用假的实例替换实际的实现(例如用内存中的实例替换SQL数据库)

我确实了解控制权的倒置(我更喜欢将这里讨论的设计模式称为“依赖注入”,因为IoC更通用-有许多种控制权,而我们仅将其中之一-初始化控制权)。我在问为什么有人需要编程语言以外的东西。我绝对可以使用代码将真实的实现替换为假的实现。此代码将表示与配置相同的内容-它将仅使用伪值初始化字段。

mary = new FakeFemale();

我确实了解DI的好处。与配置相同功能的代码相比,我不理解外部XML配置可以带来哪些好处。我认为不应避免进行编译-我每天都在编译,但我还活着。我认为DI的配置是声明式方法的不良示例。如果声明一次,并且以不同的方式多次使用,例如hibernate cfg,其中bean属性和DB列之间的映射用于保存,加载,构建搜索查询等,则声明非常有用。Spring DI配置可以轻松转换为像在此问题开头一样配置代码,可以吗?而且它仅用于bean初始化,不是吗?这意味着声明性方法不会在此处添加任何内容,是吗?

当我声明休眠映射时,我只是给休眠信息一些信息,并且它基于此信息起作用-我不告诉它怎么做。如果是春天,我的声明会告诉spring到底该做些什么-那么为什么要声明它,为什么不做呢?


最后更新:
伙计们,有很多答案告诉我有关依赖注入的知识,我知道这很好。问题是关于DI配置的目的,而不是初始化代码-我倾向于认为初始化代码更短,更清晰。到目前为止,我对问题的唯一答案是,当配置更改时,它避免了重新编译。我想我应该提出另一个问题,因为这对我来说是个大秘密,为什么在这种情况下应避免编译。


21
最后,有人有胆量问这个问题。当以牺牲(或至少降级)工具/ IDE支持为代价来更改实现时,为什么确实要避免重新编译?
Christian Klauser

3
标题似乎不太正确。作者曾说过,IOC容器很好,但是使用XML config而不是通过代码进行配置似乎有点问题(也足够公平)。我建议“通过XML或其他非代码方法配置IOC容器有什么好处?”
Orion Edwards

我提供的@Orion示例(带有Male和Female)不需要任何IOC容器。我对IOC很好;对我而言,使用容器(无论是否使用XML进行配置)仍然是一个未解决的问题。
Pavel

@Orion 2:尽管我在大多数项目中使用某种形式的IOC,但其中一些受益于IOC容器,而受益于变量赋值容器或If语句容器-仅仅语言对于我来说就足够了。我没有问题可以重新编译我正在处理的项目,并且可以方便地分离开发/测试/生产初始化代码。所以对我来说头衔很好。
Pavel Feldman'9

我发现样品有问题。原则上是注入服务,而不是数据
Jacek Cz

Answers:


40

就我自己而言,使用IoC(并使用外部配置)的主要原因之一是围绕以下两个方面:

  • 测试中
  • 生产维护

测试中

如果将测试分为3个场景(在大规模开发中这是很正常的):

  1. 单元测试
  2. 整合测试
  3. 黑匣子测试

您要针对的是最后两个测试场景(集成和黑盒),而不是重新编译应用程序的任何部分。

如果您的任何测试方案都要求您更改配置(即:使用其他组件来模拟银行集成或执行性能负载),则可以轻松地进行处理(这确实是在配置服务器的DI端的好处下)。 IoC虽然。

此外,如果您的应用程序在多个站点(具有不同的服务器和组件配置)上使用,或者在实时环境中具有更改的配置,则可以使用后期测试来验证该应用程序将处理这些更改。

生产

作为开发人员,您没有(也不应该)控制生产环境(尤其是当您的应用分发到多个客户或单独的站点时),这对我来说是同时使用IoC和外部配置的真正好处,因为需要基础结构/生产支持来调整和调整实时环境,而无需回到开发人员手中并通过测试(他们只想移动组件就需要更高的成本)。

摘要

IoC的外部配置的主要好处来自赋予其他人(非开发人员)配置应用程序的能力,以我的经验,这仅在少数情况下才有用:

  • 应用程序分发到环境会有所不同的多个站点/客户端。
  • 对生产环境和设置的有限开发控制/输入。
  • 测试方案。

在实践中,我发现即使开发出您可以控制环境的东西,随着时间的流逝,最好还是让其他人来更改配置:

  • 开发时,您不知道它何时会更改(该应用程序非常有用,您的公司将其出售给其他人)。
  • 我不希望每次请求轻微更改时都停留在更改代码上,这可以通过设置和使用良好的配置模型来处理。

注意:应用程序指的是完整的解决方案(不仅仅是可执行文件),因此,应用程序运行所需的所有文件


14

依赖注入是一种编码样式,其起源是观察到对象委托通常是比对象继承更有用的设计模式(即,对象具有-关系比对象是-关系更有用)。为了使DI起作用,还需要另外一种要素,即创建对象接口。结合了这两种强大的设计模式,软件工程师迅速意识到,他们可以创建灵活的松耦合代码,因此依赖注入的概念诞生了。但是直到对象反射在某些高级语言中可用之后,DI才真正起飞。反射组件是当今大部分时间的核心

语言必须对常规的面向对象的编程技术以及对象接口和对象反射(例如Java和C#)提供良好的支持。尽管您可以在C ++系统中使用DI模式构建程序,但由于缺乏适当语言的反射支持,因此无法支持应用程序服务器和其他DI平台,因此限制了DI模式的表现力。

使用DI模式构建的系统的优点:

  1. DI代码更容易重用,因为将“依赖”功能外推到定义明确的接口中,从而允许将其配置由适当的应用程序平台处理的单独对象随意插入其他对象。
  2. DI代码更容易测试。通过构建实现应用程序逻辑所期望的接口的“模拟”对象,可以在黑盒中测试该对象表达的功能。
  3. DI代码更加灵活。它天生就是松散耦合的代码-到了极致。这使程序员可以仅基于一端的所需接口和另一端的明确接口来选择和选择对象的连接方式。
  4. DI对象的外部(Xml)配置意味着其他人可以在无法预料的方向上自定义您的代码。
  5. 外部配置也是关注点模式的分离,因为对象初始化和对象相互依赖性管理的所有问题都可以由应用程序服务器处理。
  6. 注意,使用DI模式不需要外部配置,对于简单的互连,一个小的构建器对象通常就足够了。两者之间要在灵活性上进行权衡。构建器对象的选项不如外部可见的配置文件灵活。DI系统的开发人员必须权衡灵活性而不是便利性的优势,请注意配置文件中表示的对对象构造的小规模,细粒度控制可能会增加混乱和维护成本。

绝对地,DI代码看起来更麻烦,拥有所有配置对象以将其注入其他对象的XML文件的缺点似乎很困难。但是,这就是DI系统的重点。通过将代码对象作为一系列配置设置进行混合和匹配的能力,您可以使用第三方代码构建复杂的系统,而只需编写最少的代码。

问题中提供的示例仅涉及适当分解的DI对象库可以提供的表达能力的表面。通过一些实践和大量自律,大多数DI专业人员发现他们可以构建具有100%应用程序测试覆盖率的系统。仅这一点是非同寻常的。这不是数百行代码的小型应用程序的100%测试覆盖率,而是包含数十万行代码的应用程序的100%测试覆盖率。我不敢描述任何其他提供这种可测试性的设计模式。

您说对了,因为只有几十行代码的应用程序比几个对象以及一系列XML配置文件更容易理解。但是,与大多数强大的设计模式一样,在继续向系统添加新功能时会发现收益。

简而言之,基于DI的大型应用程序更易于调试和理解。虽然Xml配置不是“编译时检查”的,但是如果作者尝试将具有不兼容接口的对象注入到另一个对象中,那么作者意识到的所有应用程序服务都将向开发人员提供错误消息。并且大多数提供覆盖所有已知对象配置的“检查”功能。通过检查要注入的对象A是否实现了对象B所需的所有已配置对象注入的接口,可以轻松而快速地完成此操作。


4
了解DI的好处。与配置相同功能的代码相比,我不明白外部XML配置可以带来哪些好处。您提到的好处是由DI设计模式提供的。问题是与纯初始化代码相比,DI配置的好处。
帕维尔·费尔德曼

>外部配置也是分离...配置分离是DI的核心,这是好的。而且它可以使用初始化代码来实现圆顶。与初始化代码相比,cfg增加了什么?对我来说,cfg的每一行似乎都有相应的初始化代码行。
帕维尔·费尔德曼

7

这是一个非常棘手的问题,但是我倾向于同意大量的xml配置并不能真正带来很多好处。我希望我的应用程序尽可能地减少依赖关系,包括庞大的框架。

它们很多时候简化了代码,但是它们也具有复杂性的开销,这使得跟踪问题变得相当困难(我亲眼目睹了此类问题,对于Java直截了当的人,我会更容易处理)。

我想这取决于样式,以及您是否满意……您是否喜欢自己开发解决方案并从内到外受益,还是希望依靠现有的解决方案,而当配置不当时可能会遇到困难?就对吗?这都是一个权衡。

但是,XML配置有点像是我的烦恼……我会尽一切努力避免这样做。


5

每当您可以将代码更改为数据时,您都朝着正确的方向迈出了一步。

将任何内容编码为数据意味着您的代码本身更加通用和可重用。这也意味着您可以使用完全适合您的语言来指定您的数据。

而且,可以将XML文件读入GUI或其他工具中,并易于进行实用的操作。您将如何使用代码示例来做到这一点?

我一直在考虑大多数人将代码实现为数据的事情,这使得剩下的代码更加干净。我发现人们将无法以代码而不是数据来创建菜单,这是难以想象的。很显然,由于存在样板,因此在代码中执行菜单是完全错误的。


有意义,没有从这个角度考虑
Pavel Feldman

7
然后,人们通常会
另辟go径

@Casebash这是一个有趣的观点-我会对一个示例非常感兴趣。我发现我可以进入数据的任何内容都会有所帮助。我还发现,如果我按照您的意思说的话,由于它是DSL,因此实际上已经得到了改进,但是即使这样,创建一种全新的语言也需要认真的理由。
比尔K

1
“只要您能将代码更改为数据,就可以朝着正确的方向迈出一步。” 欢迎使用软编码反模式。
拉德瓦尔德

@Raedwald您正在谈论的是外部化,如果您不知道自己在做什么,这将非常困难(以及某人不称职的尝试,失败并称其为反模式的原因)。更积极的例子是Injection,Iterators ,几乎所有带有注释的内容,任何以数组初始化的内容。大多数优秀的编程结构都是试图找出代码中的差异,并结合剩下的内容,以更好地进行分组和管理的方式来进行驱动。
Bill K

3

使用DI容器的原因是您不必在代码中预先配置十亿个属性,而这些属性只是简单的getter和setter。您是否真的想用新的X()对所有代码进行硬编码?当然,您可以使用默认值,但是DI容器允许创建单例,这非常容易,并且可以使您专注于代码的细节,而不是初始化它的其他任务。

例如,Spring允许您实现InitializingBean接口并添加afterPropertiesSet方法(还可以指定“ init-method”以避免将代码耦合到Spring)。这些方法将允许您确保在启动时正确配置了在类实例中指定为字段的任何接口,然后您不再需要对getter和setter进行空检查(假设您确实允许单例保持线程安全) )。

此外,使用DI容器进行复杂的初始化要比自己进行复杂得多。例如,我协助使用XFire(不是CeltiXFire,我们仅使用Java 1.4)。该应用程序使用了Spring,但不幸的是,它使用了XFire的services.xml配置机制。当元素集合需要声明其具有零个或多个实例而不是一个或多个实例时,我必须重写此特定服务提供的某些XFire代码。

在其Spring bean模式中定义了某些XFire默认值。因此,如果我们使用Spring来配置服务,则可以使用Bean。相反,发生的事情是我不得不在services.xml文件中提供特定类的实例,而不是使用bean。为此,我需要提供构造函数并设置XFire配置中声明的引用。我需要进行的真正更改要求我重载单个类。

但是,由于使用了services.xml文件,我不得不创建四个新类,根据其构造函数中Spring配置文件中的默认值设置它们的默认值。如果我们能够使用Spring配置,那么我可以这样说:

<bean id="base" parent="RootXFireBean">
    <property name="secondProperty" ref="secondBean" />
</bean>

<bean id="secondBean" parent="secondaryXFireBean">
    <property name="firstProperty" ref="thirdBean" />
</bean>

<bean id="thirdBean" parent="thirdXFireBean">
    <property name="secondProperty" ref="myNewBean" />
</bean>

<bean id="myNewBean" class="WowItsActuallyTheCodeThatChanged" />

相反,它看起来像这样:

public class TheFirstPointlessClass extends SomeXFireClass {
    public TheFirstPointlessClass() {
        setFirstProperty(new TheSecondPointlessClass());
        setSecondProperty(new TheThingThatWasHereBefore());
    }
}

public class TheSecondPointlessClass extends YetAnotherXFireClass {
    public TheSecondPointlessClass() {
        setFirstProperty(TheThirdPointlessClass());
    }
}

public class TheThirdPointlessClass extends GeeAnotherXFireClass {
    public TheThirdPointlessClass() {
        setFirstProperty(new AnotherThingThatWasHereBefore());
        setSecondProperty(new WowItsActuallyTheCodeThatChanged());
    }
}

public class WowItsActuallyTheCodeThatChanged extends TheXFireClassIActuallyCareAbout {
    public WowItsActuallyTheCodeThatChanged() {
    }

    public overrideTheMethod(Object[] arguments) {
        //Do overridden stuff
    }
}

因此,最终结果是必须将四个附加的,几乎没有意义的Java类添加到代码库中,以实现获得一个附加的类和一些简单的依赖容器信息的效果。这不是“证明规则的例外”,而是规则……在DI容器中已经提供了属性,而您只是为了适应特殊情况而对其进行更改时,处理代码中的怪癖会更加简洁。这种情况经常发生。


3

我有你的答案

每种方法显然都需要权衡取舍,但是外部化的XML配置文件对于企业开发非常有用,在企业开发中,使用构建系统来编译代码,而不是IDE。使用构建系统,您可能需要向代码中注入某些值,例如构建的版本(每次编译时都必须手动进行更新可能很麻烦)。当您的构建系统将代码从某个版本控制系统中提取出来时,痛苦会更大。在编译时修改简单值将需要您更改文件,提交文件,进行编译,然后为每次更改每次还原。这些不是您要提交到版本控制中的更改。

有关构建系统和外部配置的其他有用用例:

  • 为不同的构建为单个代码库注入样式/样式表
  • 为单个代码库注入不同组的动态内容(或对它们的引用)
  • 为不同的构建/客户端注入本地化上下文
  • 将Web服务URI更改为备份服务器(当主服务断开时)

更新:以上所有示例都涉及不一定需要依赖类的事情。但是,您可以轻松建立同时需要复杂对象和自动化的情况-例如:

  • 想象一下,您有一个可以监视网站流量的系统。根据并发用户数,它可以打开/关闭日志记录机制。也许在机制关闭时,将存根对象放在其位置。
  • 想象一下,您有一个Web会议系统,其中您希望根据用户数量切换出进行P2P的能力。

+1用于在顶部突出显示企业方面。测试写得不好的旧代码有时可能是几天的噩梦。
理查德·勒·马苏里尔

2

您无需在每次更改配置时都重新编译代码。它将简化程序的部署和维护。例如,您只需在配置文件中进行一次更改即可将一个组件交换为另一个组件。


部署?可能...维护部署?大概...代码维护?我倾向于认为没有...通过框架进行调试通常会让人头疼,而pojos在这方面要容易得多。
Mike Stone

1
迈克,我什么也没说。我们都知道XML配置很烂:)
aku

嗯..您多久更改一次组件而无需重新编译,其用途是什么?我了解是否有人更改了数据库凭据并且不想重新编译该程序-他可能不是开发该程序的人。但是除了开发人员更改弹簧配置外,我几乎无法想象
Pavel Feldman

Pavel通常在您必须将程序部署到数百个客户端时发生这种情况。在这种情况下,更改配置要比部署产品的新版本容易得多。你说的关于开发者是正确的。通常,开发人员会创建新的cfg,并由管理员进行部署。
aku

2

您可以为女友加入新的实现方式。这样就可以注入新的女性而不用重新编译代码。

<bean id="jane" class="foo.bar.HotFemale">
  <property name="age" value="19"/>
</bean>
<bean id="mary" class="foo.bar.Female">
  <property name="age" value="23"/>
</bean>
<bean id="john" class="foo.bar.Male">
  <property name="girlfriend" ref="jane"/>
</bean>

(以上假设Female和HotFemale实现相同的GirlfFriend接口)


为什么不重新编译就修改逻辑被认为是一个好主意?
帕维尔·费尔德曼

我绝对可以做HotFemale jane = new HotFmale(); jane.setAge(19); john.setGirlfriend(jane); 因此,唯一的区别是可以更改cfg而无需重新编译?讨论Spring时,这似乎是常见的答案。为什么?!为什么最好避免编译?
帕维尔·费尔德曼

好吧,我可以更好地测试代码,也可以模拟女性对象。
Paul Whelan

@Pavel Feldman:因为如果您已经在客户端上部署了应用程序,这会更容易。
AndreiRînea,2010年

1

在.NET世界中,大多数IoC框架都提供XML和代码配置。

例如,StructureMap和Ninject使用流畅的界面来配置容器。您不再受限于使用XML配置文件。Spring也存在于.NET中,由于它是他的主要历史配置界面,因此它在很大程度上依赖XML文件,但是仍然可以通过编程方式配置容器。


真是太棒了,我终于可以使用打算使用的代码:)但是,为什么我什至需要除编程语言之外的任何东西来做这些事情?
帕维尔·费尔德曼

我认为这是因为XML允许运行时更改,或者至少允许配置更改,而不必重新编译项目。
罗曼·韦迪耶

1

易于将部分配置组合为最终的完整配置。

例如,在Web应用程序中,通常在单独的配置文件中指定模型,视图和控制器。使用声明性方法,您可以加载,例如:

  UI-context.xml
  Model-context.xml
  Controller-context.xml

或加载不同的UI和一些其他控制器:

  AlternateUI-context.xml
  Model-context.xml
  Controller-context.xml
  ControllerAdditions-context.xml

要在代码中执行相同的操作,需要用于组合部分配置的基础结构。用代码做并非不可能,但是使用IoC框架当然更容易做。


1

通常,重要的一点是在编写程序之后,在更改配置。使用代码中的配置,您隐式地假设更改它的人具有与原始作者相同的技能和对源代码的访问权限。

在生产系统中,将设置的某些子集(例如您的年龄)提取到XML文件中,并允许例如系统管理员或支持人员更改值,而不用赋予他们全部控制源代码或其他设置的全部权限,或者仅仅是将它们从复杂性中分离出来。


这是有道理的,但是弹簧配置通常往往很复杂。尽管更改年龄很容易,但是sysadmin仍然必须处理他不必完全理解的大型xml文件。将应该配置的部分提取成比spring XML config更简单的方法不是更好吗?像属性文件一样,只有一行“ age = 23”,并且不允许管理员更改需要内部程序结构知识的其他详细信息,例如类名等。
帕维尔·费尔德曼

我最近正在从事一个包含Java代码和XSLT的项目。该团队是由Java方面的专家(可能不太熟悉XML和XSLT)组成的。以及非常擅长使用XML和XSLT(对Java不太满意)的人。由于配置将由第二组管理,因此使用Spring并具有XML配置是很有意义的。换句话说,Spring解决了团队中的分工问题。它没有解决“技术”问题;从某种意义上说,可以使用Java代码轻松完成配置。
达伍德·伊本·卡里姆

什么时候“支持人员”会知道什么必须更改在依赖注入容器中创建的某些类?真的假设这样做是开发人员的工作吗?
Jimbo

这正是提取配置值(例如与您集成的系统的URL)有意义的原因:支持人员编辑属性文件或(在最坏的情况下)XML文件,编译后的Java类保持不变。
Miro A.

1

从春季的角度来看,我可以给你两个答案。

首先,XML配置不是定义配置的唯一方法。多数事情都可以使用注释进行配置,而XML必须完成的事情就是对您始终没有编写的代码进行配置,例如从库中使用连接池。Spring 3包含一种使用Java定义DI配置的方法,类似于示例中的手动DI配置。因此,使用Spring并不意味着您必须使用基于XML的配置文件。

其次,Spring不仅仅是一个DI框架。它还具有许多其他功能,包括事务管理和AOP。Spring XML配置将所有这些概念混合在一起。通常,我在同一配置文件中指定Bean依赖项,事务设置,并添加实际上在后台使用AOP处理的会话范围的Bean。我发现XML配置提供了更好的位置来管理所有这些功能。我还觉得基于注释的配置和XML配置的扩展性比基于Java的配置更好。

但是我确实明白您的意思,并且在Java中定义依赖项注入配置没有任何错误。我通常在单元测试中以及在我做一个很小的项目时都这样做,而我没有添加DI框架。我通常不指定Java配置,因为对我来说,这就是我选择使用Spring时要尽量避免编写的那种管道代码。尽管这是首选,但这并不意味着XML配置优于基于Java的配置。


0

Spring也有一个属性加载器。我们使用这种方法来设置取决于环境的变量(例如,开发,测试,验收,生产等)。例如,这可能是要收听的队列。

如果没有理由更改属性,也没有理由以这种方式配置它。


0

您的情况非常简单,因此不需要像Spring这样的IoC(控制反转)容器。另一方面,当您“对接口进行编程,而不是对实现进行编程”(这是OOP中的一种好习惯)时,您可以拥有如下代码:

IService myService;
// ...
public void doSomething() {
  myService.fetchData();
}

(请注意,myService的类型是IService-接口,而不是具体的实现)。现在,让您的IoC容器在初始化期间自动提供IService的正确具体实例非常方便-当您有许多接口和许多实现时,手动完成操作可能很麻烦。IoC容器(依赖注入框架)的主要优点是:

  • 接口之间的映射及其具体实现的外部配置
  • IoC容器处理一些棘手的问题,例如解决复杂的依赖关系图,管理组件的生命周期等。
  • 节省编码时间,因为您以声明方式而不是在过程代码中提供映射
  • 控制反转的原理使单元测试变得容易,因为您可以用假的实例替换实际的实现(例如用内存中的实例替换SQL数据库)

0

在XML配置文件中初始化将简化与将您的应用程序部署在其计算机上的客户端的调试/调整工作。(因为它不需要重新编译+替换二进制文件)


-2

最具吸引力的原因之一是“ 好莱坞原则 ”:不要打电话给我们,我们会打电话给您。不需要组件来查找其他组件和服务本身;相反,它们是自动提供给它的。在Java中,这意味着不再需要在组件内部进行JNDI查找。

孤立地对组件进行单元测试也要容易得多:您无需使用实际的实现,而是简单地使用(可能是自动生成的)模拟,而不是为其提供所需组件的实际实现。


这个答案是关于依赖注入的。我知道这是什么,我知道这是件好事,并在问题的第一句话中明确指出。问题是与普通初始化代码相比,DI配置的好处。
帕维尔·费尔德曼

并未真正回答问题
Casebash
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.