什么是dependency injection和Spring框架?

可能重复:
什么是dependency injection?
spring究竟是什么?

我想知道Spring Framework是什么? 为什么以及何时应该在Java Enterprise开发中使用它? 答案是“dependency injection框架”。 好吧,使用dependency injection框架时我们有什么优势? 使用setter值和/或构造函数参数描述类的想法对我来说似乎很奇怪。 为什么这样? 因为我们可以在不重新编译项目的情况下更改属性? 这就是我们所获得的一切吗?

那么,我们应该在beans.xml中描述哪些对象? 所有对象还是只有几个?

最简单的答案是受欢迎的

我们使用dependency injection(DI)来实现松散耦合 。 选择任何特定的DI容器并不重要。

每次使用new关键字创建类的实例时,都会将代码紧密地耦合到该类,并且您将无法用不同的实例替换该特定实现(至少在没有重新编译代码的情况下)。

这在C#中看起来像这样(但在Java中是等效的):

 public class MyClass { public string GetMessage(int key) { return new MessageService().GetMessage(key) } } 

这意味着如果您以后想要使用不同的MessageService,则不能。

另一方面,如果您将接口注入到类中并遵循Liskov Substition Principle ,您将能够独立地改变使用者和服务。

 public class MyClass { private readonly IMessageService messageService; public MyClass(IMessageService messageService) { if(messageService == null) { throw new ArgumentNullException("messageService"); } this.messageService = messageService; } public string GetMessage(int key) { return this.messageService.GetMessage(key) } } 

虽然这看起来更复杂,但我们现在已经设法遵循单一责任原则 ,确保每个协作者只做一件事,并且我们可以彼此独立地改变。

此外,我们现在可以在不改变类本身的情况下改变MyClass的行为,从而坚持开放/封闭原则 。

重新配置被高估了。 使用DI最重要的是可测试性 。 由于您的类不依赖于实现,而是依赖于抽象,您可以在unit testing中用模拟/存根替换它们。

没有DI:

 class SaleAction{ private BillingService billingService; public SaleAction(){ billingService = new CreditCardService(); //dependency is hardcoded } public void pay(long amount){ //pre payment logic billingService.pay(amount); //post payment logic } } 

在该示例中,假设您要对SaleAction的预付款逻辑和后付款逻辑进行unit testing…您不能,因为SaleActionCreditCardService耦合,并且运行您的测试可能会生成虚假付款。

现在与DI相同的例子:

  class SaleAction{ private BillingService billingService; public SaleAction(BillingService service){ billingService = service; //DI } public void pay(long amount){ //pre payment logic billingService.pay(amount); //post payment logic } } 

现在SaleAction与任何实现分离,这意味着在你的测试中你可以做SaleAction action = new SaleAction(new DummyBillingService());

希望有所帮助,还有关于DI 文章,由Martin Fowler撰写,你可以在这里找到

Spring已经变成了一个巨大的框架,如果你只是试图绕过dependency injection,那可能会让你感到困惑。 Google Guice项目很小,只使用纯Java进行DI – 没有XML,也没有额外内容。 还有一个很好的介绍性video解释DI。 http://code.google.com/p/google-guice/

这是一篇很好的文章,解释了spring的想法。 (作者:Spring Johnson框架的创始人Rod Johnson)

你已经有了一些很好的答案,我想解决你的一些具体问题:

使用setter值和/或构造函数参数描述类的想法对我来说似乎很奇怪。 为什么这样? 因为我们可以在不重新编译项目的情况下更改属性? 这就是我们所获得的一切吗?

一开始看起来确实很奇怪但重点是容器负责插入对象的依赖关系,对象本身并不负责。 beans.xml中配置的对象的范围由Spring管理,因此我们不必担心在没有正确依赖项的情况下实例化的事情(只要配置正确,我就会知道编写unit testing检查弹簧配置是否符合我的要求。)

那么,我们应该在beans.xml中描述哪些对象? 所有对象还是只有几个?

beans.xml中描述的对象类型主要是组件 – 控制器,服务,数据访问对象,以及它们所需要的东西,如事务管理器,hibernate会话工厂,数据源等。 域对象通常从数据访问对象中检索或直接实例化,因为除了其他域对象(或者比域类更独立的实用程序类)之外,它们不依赖于任何其他域对象。

我想我可以解决这个问题,虽然我不确定任何答案都会令人满意。

简单的答案是Spring是技术的组合:

  1. dependency injection,它使用好莱坞原则来帮助您保持界面和实现分离;
  2. 面向方面的编程,它将交叉切割关注点分离为可以声明方式应用的模块。 AOP的“hello world”是日志记录,但它遍及Spring(例如事务,远程处理的动态代理,安全性等)。想想servletfilter,你就会有这个想法;
  3. 库,以帮助执行常见任务,如持久性(JDBC,Hibernate,iBatis,JDO,JPA等),远程处理(RMI,HTTP,Web服务),异步消息传递(消息驱动的POJO),validation和绑定,Web MVC(Spring或Struts),电子邮件,日程安排,安全等实用程序。

但更深层次的答案是,您将获得Rod Johnson作为Java EE项目顾问的经验。 他将他在演出中为他工作的东西提炼成Interface 21 / Spring,现在你可以免费获得所有这些。

Spring团队编写的代码经过精心设计,测试并遵循标准,比我写的任何内容都要严格。 (想象一下Juergen Hoeller对Rod Johnson的威胁,因为他的代码在签入之前不符合标准。)我可以依靠他们的框架代码来使用它并专注于我的业务问题。 我不是一次又一次地写锅炉板代码。

对我来说,Spring更多的是一个架构模板,它可以作为创建Web应用程序的指南。 有些人可能会说这是过度设计的,对于某些问题他们是正确的,但对于我经常遇到的那些问题,Spring只是门票。

至于子问题:

使用dependency injection框架时我们有什么优势?

对象不必负责管理其依赖项。 Spring的应用程序上下文实际上只是GoF的一个大型工厂模式。 它鼓励您设计界面,以便您可以根据需要更改实施。 你的持久性接口今天可能会使用JDBC实现,明天是Hibernate; 您可能决定自动生成代理来管理其事务行为。 如果编码到接口,则不必更改任何客户端代码。

使用setter值和/或构造函数参数描述类的想法对我来说似乎很奇怪。 为什么这样? 因为我们可以在不重新编译项目的情况下更改属性? 这就是我们所获得的一切吗?

奇怪? 您不在代码中使用属性或构造函数? 你这样做是因为这是大多数Java类的编写方式。 Spring仅使用这些机制作为向类提供依赖关系的方法。

那么,我们应该在beans.xml中描述哪些对象? 所有对象还是只有几个?

只有具有依赖关系的bean。 我仍然为特定方法的本地对象调用“new”。 它们在方法范围内创建,使用和垃圾收集。 那些不需要受Spring控制。

意见:找出你试图用DI解决的问题,并采用最适合的框架。 Spring可能会增加您的问题的复杂性。

( Martin Fowler关于DI的第一篇文章之一 。我认为DI这个词在本文中被创造出来。)

这是Bob Lee给出的一个很好的video和他关于Guice的两项研究(Guice是像Spring这样的dependency injection框架)。 前10分钟左右是为什么Guice(或dependency injection)会比替代(工厂)更好,所以它不仅仅是关于Guice。

也许你不应该在不了解基本架构和设计问题的情况下尝试进行“Java企业开发”? 我建议您找到一位愿意帮助您的经验丰富的同事,或者投入更多精力阅读这些书籍,或者按照课程学习。

无论如何,你的问题没有“简单的答案”。

dependency injection是缺少虚拟类的一种解决方法!

注意: 如果您不知道虚拟课程是什么,请参阅“虚拟课程,任何人?”