关于java:什么是依赖注入&

What are Dependency Injection & Spring Framework about?

本问题已经有最佳答案,请猛点这里访问。

Possible Duplicates:
What is dependency injection?
What exactly is Spring for?

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

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

最简单的答案是受欢迎的


我们使用依赖注入(DI)来实现松耦合。选择任何特殊的DI容器都没有那么重要。

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

这看起来像C(在爪哇相当):

1
2
3
4
5
6
7
public class MyClass
{
    public string GetMessage(int key)
    {
        return new MessageService().GetMessage(key)
    }
}

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

另一方面,如果您向类中注入一个接口并遵循Liskov子状态原则,那么您将能够独立地改变使用者和服务。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
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最重要的是可测试性。因为您的类不依赖于实现,而是依赖于抽象,所以您可以在单元测试中用mock/stub替换它们。

例子

没有DI:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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的例子也一样:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
 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的文章,你可以在这里找到。


Spring已经变成了一个巨大的框架,如果您只是试图将您的头围绕在依赖注入上,那么这可能会让您感到困惑。谷歌Guice项目很小,只有纯Java的DI——没有XML,也没有额外的。还有一个很好的介绍视频来解释DI。http://code.google.com/p/google-guice/


这篇文章很好地解释了春天的想法。(作者Rod Johnson,Spring框架的创始人)


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

The idea of describing classes with setter values and/or constructor parameters seems strange to me. Why do that? Because we can change the properties without recompiling the project? Is that all what we gain?

< /块引用>

一开始看起来确实很奇怪,但问题是容器负责插入对象的依赖项,对象本身不负责。beans.xml中配置的对象的范围是由spring管理的,因此我们不必太担心没有正确的依赖关系而被实例化的事情(只要配置是正确的,就知道我会编写单元测试来检查spring配置是否在做我想做的事情)。

Then, what objects should we describe in beans.xml ? All objects or only a few ?

< /块引用>

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


我想我可以试着回答这个问题,尽管我不确定任何答案是否令人满意。

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

  • 依赖注入,它使用好莱坞原则来帮助您保持接口和实现的独立性;
  • 面向方面的编程,它将横切关注点隔离到可以声明地应用的模块中。AOP的"hello world"正在进行日志记录,但是它已经是一个春天了(例如事务、用于远程处理的动态代理、安全性等),您可以考虑使用servlet过滤器,这样您就有了这个想法;
  • 用于帮助执行常见任务的库,如持久性(JDBC、Hibernate、iBatis、JDO、JPA等)、远程处理(RMI、HTTP、Web服务)、异步消息传递(消息驱动的POJO)、验证和绑定、Web MVC(Spring或Struts)、电子邮件、调度、安全性等实用程序。
  • 但更深层的答案是,你得到了Rod Johnson作为JavaEE项目顾问的经验。他把为他工作的东西提炼成了21/Spring界面,现在你可以免费享受这些好处了。

    Spring团队编写的代码设计、测试和遵循标准比我写的任何东西都更加严格。(想象一下JuergenHoellerBrowbeattrodJohnson,因为他的代码在签入之前不符合标准。)当我使用它们的框架代码时,我可以依靠它们,集中精力解决我的业务问题。我不会一次又一次地写样板代码。

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

    至于子问题:

    What advantages do we have when using dependency injection frameworks?

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

    The idea of describing classes with setter values and/or constructor parameters seems strange to me. Why do that? Because we can change the properties without recompiling the
    project? Is that all what we gain?

    奇怪?在代码中不使用属性或构造函数?之所以这么做,是因为大多数Java类都是这样编写的。Spring只使用这些机制作为向类提供依赖性的方法。

    Then, what objects should we describe in beans.xml ? All objects or only a few ?

    只有具有依赖性的bean。我仍然为特定方法的本地对象调用"new"。它们是在方法范围内创建、使用和垃圾收集的。这些不必由弹簧控制。


    也许你不应该尝试进行"Java企业开发",而不需要了解一些基本的架构和设计问题。我建议你要么找一个愿意帮助你的有经验的同事,要么花更多的精力去读那些书,要么去学一门课程。

    在任何情况下,你的问题都没有"简单的答案"。


    这是BobLee提供的一个很好的视频,他正在研究Guice(Guice是一个类似Spring的依赖注入框架)。前10分钟左右是关于为什么Guice(或依赖注入)比其他(工厂)更好,所以这不仅仅是关于Guice。


    意见:找出您试图用DI解决的问题,并采用最适合的框架。春天会给你的问题增加很多复杂性。

    (马丁·福勒关于DI的第一篇文章之一。我认为DI这个词是在这篇文章中创造的。)


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

    nbsp;

    注意:如果您不知道什么是虚拟类,请参考"虚拟类,任何人?".