什么是依赖注入&关于Spring框架?

时间:2009-12-30 13:23:07

标签: java spring dependency-injection

  

可能重复:
  What is dependency injection?
  What exactly is Spring for?

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

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

欢迎最简单的答案

10 个答案:

答案 0 :(得分:22)

我们使用依赖注入(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)
    }
}

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

此外,我们现在可以在不改变类本身的情况下改变MyClass的行为,从而坚持Open/Closed Principle

答案 1 :(得分:12)

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

示例

没有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的预付款逻辑和后付款逻辑进行单元测试...您不能因为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撰写,你可以找到here

答案 2 :(得分:3)

Here's a good article解释了春天的想法。 (作者:Rod Johnson,Spring框架的创始人)

答案 3 :(得分:3)

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

答案 4 :(得分:2)

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

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

  1. 依赖注入,它使用好莱坞原则来帮助您保持界面和实现的分离;
  2. 面向方面的编程,它将交叉切割问题隔离到可以声明性地应用的模块中。 AOP的“hello world”是日志记录,但它遍及Spring(例如事务,远程处理的动态代理,安全性等)。想想servlet过滤器,你就会有这个想法;
  3. 库,用于帮助执行常见任务,如持久性(JDBC,Hibernate,iBatis,JDO,JPA等),远程处理(RMI,HTTP,Web服务),异步消息传递(消息驱动的POJO),验证和绑定,Web MVC (Spring或Struts),电子邮件,日程安排,安全等实用程序。
  4. 但更深层次的答案是,您将获得Rod Johnson作为Java EE项目顾问的经验。他将自己在演出中为他工作的东西提炼成Interface 21 / Spring,现在你可以免费获得所有这些。

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

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

    关于子问题:

      

    使用依赖注入框架时我们有什么优势?

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

      

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

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

      

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

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

答案 5 :(得分:2)

您已经在这里找到了一些好的答案,我想解决您的几个具体问题:

  
    

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

  

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

  
    

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

  

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

答案 6 :(得分:1)

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

(其中一个first articles about DI by Martin Fowler。我认为DI这个词在本文中被创造出来。)

答案 7 :(得分:1)

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

答案 8 :(得分:1)

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

在任何情况下,您的问题都没有“简单的答案”。

答案 9 :(得分:0)

依赖注入是缺少虚拟类的解决方法!

注意:如果您不知道哪些虚拟课程,请参阅"Virtual classes, anyone?"