Java 了解DI框架的需求

Java 了解DI框架的需求,java,spring,dependency-injection,Java,Spring,Dependency Injection,这可能是一个天真的问题。我目前正在学习Spring框架和依赖注入。虽然DI的基本原理很容易掌握,但您为什么需要一个复杂的框架来实现它,这一点并不明显 考虑以下几点: public abstract class Saw { public abstract void cut(String wood); } public class HandSaw extends Saw { public void cut(String wood) { // chop it

这可能是一个天真的问题。我目前正在学习Spring框架和依赖注入。虽然DI的基本原理很容易掌握,但您为什么需要一个复杂的框架来实现它,这一点并不明显

考虑以下几点:

public abstract class Saw
{
    public abstract void cut(String wood);
}

public class HandSaw extends Saw
{
    public void cut(String wood)
    {
        // chop it up
    }
}

public class ChainSaw extends Saw
{
    public void cut(String wood)
    {
        // chop it a lot faster
    }
}

public class SawMill
{
    private Saw saw;

    public void setSaw(Saw saw)
    {
        this.saw = saw;
    }

    public void run(String wood)
    {
        saw.cut("some wood");
    }
}
然后你可以简单地做:

Saw saw = new HandSaw();
SawMill sawMill = new SawMill();
sawMill.setSaw(saw);
sawMill.run();
这相当于:

<bean id="saw" class="HandSaw"/>

<bean id="sawMill" class="SawMill">
   <property name="saw" ref="saw"/>
</bean>
诚然,这是一个精心设计的示例,对于更复杂的对象关系,隐藏XML文件可能比以编程方式编写XML文件更有效,但肯定还有更多的内容吗

(我知道Spring框架不止这些,但我正在考虑是否需要DI容器。)

在第一个示例中,在中游更改依赖项也很简单:

// gotta chop it faster
saw = new ChainSaw();
sawMill.setSaw(saw);
sawMill.run();

如果硬编码插入的类,则需要该类在编译时可用。使用配置文件,您可以在运行时更改使用过的saw(在您的示例中),而无需重新编译,甚至可以使用从刚刚放置在类路径中的新jar中获取的saw。如果值得的话,额外的复杂性取决于您必须解决的任务。

重要的是要理解Spring基本上是两件事,一件是建立在另一件之上的:

  • 轻量级DI/IoC框架和实现该框架的类(如XML应用程序上下文等);及
  • 它是一个轻量级容器
  • (2) 是Spring代码的主体。基本上,选择一种Java技术,您可能会发现Spring为它提供了助手类。这样,您就可以使用ActiveMQ、Sun One MQ或任何东西,并将它们抽象为Spring JmsTemplate,数据访问技术、Web服务等也是如此


    所有这些助手都使用(1)将它们连接在一起。

    我有一个完全相同的问题,答案是:
    当然,你可以做你在“那么你可以简单地做:…”(我们称之为“A类”)中描述的事情。然而,这会将类A耦合到手锯,或者耦合到锯木厂类所需的所有依赖项。为什么要将A耦合到HandSaw?或者,如果采用更现实的场景,为什么要将我的业务逻辑耦合到DAO层所需的JDBC连接实现?
    我当时提出的解决方案是“然后将依赖项进一步移动”——好的,现在我已经将我的视图与JDBC连接相耦合,我应该只处理HTML(或者Swing,选择您的风格)

    由XML(或JavaConfig)配置的DI框架通过让您“获得所需的服务”来解决这个问题。您不在乎它是如何初始化的,也不在乎它需要做什么——您只需要获取服务对象并激活它


    另外,您对“plus”有一个错误的概念:(
    SawMill-springSawMill=(SawMill)context.getBean(“SawMill”);springSawMill.run();
    )-您不需要从上下文获取锯木厂bean-锯木厂bean应该已经被DI框架注入到您的对象(类a)中。因此,您只需使用“sawMill.run()”,而不必使用…getBean(…),不管它来自何处、是谁初始化的以及如何初始化的。不管怎么说,它可以直接转到/dev/null,或者测试输出,或者真正的CnC引擎。。。关键是——你不在乎。你所关心的只是你的小小的类A,它应该做它约定要做的事情——激活锯木厂。

    我通常不关心XML或基于反射的DI,因为在我的用例中,它增加了不必要的复杂性。相反,我通常会选择某种形式的手动DI,对我来说,这似乎更自然,并且具有大多数好处

    public class SawDI{
        public Saw CreateSaw(){
            return new HandSaw();
        }
    
        public SawMill CreateSawMill(){
            SawMill mill = new SawMill();
            mill.SetSaw(CreateSaw());
            return mill;
        }
    }
    
    // later on
    
    SawDI di = new SawDI();
    SawMill mill = di.CreateSawMill();
    

    这意味着我仍然集中了耦合,并具有所有的优势,而不依赖于更复杂的DI框架或XML配置文件。

    最重要的一件事(如果不是全部的话)DI容器/库还为您带来了截取通过DI创建的所有实例的方法的可能性。

    Spring帮助您理解甚至鼓励DI模型。然而,我不相信你一定要有春天

    您可以使用Java的配置文件进行调试、重构和代码分析

    我建议您将这些java配置文件放在另一个包中,但它们在其他方面等同于XML配置文件。如果这很重要,您甚至可以动态加载这些文件

    诚然,这是一个精心设计的示例,对于更复杂的对象关系,隐藏XML文件可能比以编程方式编写XML文件更有效,但肯定还有更多的内容吗

    我认为将“连接”放在配置文件中比在代码中手动执行更有意义,原因如下:

  • 配置在代码外部
  • 只需对外部(XML)文件进行更改即可(告诉锯木厂使用不同的锯切实例),无需更改代码、重新编译、重新部署等
  • 当您有几十个类和几层注入(例如:您有一个web
    控制器
    类,该类获得一个
    服务
    类,该类包含您的业务逻辑,该类使用
    DAO
    从数据库获得
    Saw
    s,该类将
    数据源
    注入数据库,等等),手动连接协作者是乏味的,需要几十行代码,这些代码除了连接之外什么也不做
  • 这并不是一个明确的“好处”,但通过将所有的“连接”放在代码外部,我认为这有助于重新向开发人员灌输依赖注入的核心思想,特别是编码到接口而不是实现的思想。通过手动接线,可以很容易地回到旧的方式

  • Spring有三个同样重要的功能:

  • 依赖注入
  • 面向方面编程
  • 有助于使用p的框架类库
    public class SawDI{
        public Saw CreateSaw(){
            return new HandSaw();
        }
    
        public SawMill CreateSawMill(){
            SawMill mill = new SawMill();
            mill.SetSaw(CreateSaw());
            return mill;
        }
    }
    
    // later on
    
    SawDI di = new SawDI();
    SawMill mill = di.CreateSawMill();
    
    SawMill sawMill = new SawMill(new HandSaw());
    sawMill.run();