什么是简单英语中的AOP,依赖注入和控制反转

时间:2010-04-03 18:03:09

标签: java spring dependency-injection inversion-of-control aop

我试图了解AOP,依赖注入和控制SPRING相关概念的反转,但我很难理解它。

任何人都可以用简单的英语解释这个吗?

6 个答案:

答案 0 :(得分:47)

我理解你的困惑,我花了一些时间来理解这些概念是如何相互关联的。所以这是我(以某种方式个人)解释所有这些:

<强> 1。控制倒置

Inversion of control是一个相当通用的设计原则,它指的是行为规范与实际执行时的解耦。比如,

myDependency.doThis();

myDependency.onEventX += doThis();

在后者中,没有直接调用更灵活。在其一般形式中,控制反转涉及观察者模式事件回调

<强> 2。依赖倒置

依赖倒置是另一种设计原则。粗略地说,它说更高级别的抽象不应该直接依赖于较低级别的抽象;这种结果确实存在于一种设计中,如果没有较低级别的抽象,则无法重用更高级别的抽象。

 class MyHighLevelClass {
     MyLowLevelClass dep = new MyLowLeverClass();
 }

 class App {
     void main() {  new HighLevelClass().doStuff(); }
 }

此处,MyHighLevelClass无法在不访问MyLowLevelClass的情况下进行编译。为了打破这种耦合,我们需要使用接口抽象低级别类,并删除直接实例化。

class MyLowLevelClass implements MyUsefulAbstraction { ... }

class MyHighLevelClass {

    MyUsefulAbstraction dep;

    MyHighLevelClass( MyUsefulAbstraction dep ) {
        this.dep = dep;
    }
}

class App {
     void main() {  new HighLevelClass( new LowLevelClass() ).doStuff(); }
 }

请注意,您不需要像容器这样的特殊内容来强制执行依赖项反转,这是一个原则。好的读物是{Uncle Bob的The Dependency Inversion Principle

第3。依赖注入

现在是依赖注入。给我dependency injection = IoC + dependency inversion

  1. 依赖是在外部提供的,因此我们强制执行依赖性反转原则
  2. 容器设置依赖关系(不是我们)所以我们谈论控制反转
  3. 在上面提供的示例中,如果使用容器实例化对象并自动注入构造函数中的依赖项(我们经常说DI容器),则可以完成依赖注入:

     class App {
         void main() {  DI.getHighLevelObject().doStuff(); }
     }
    

    请注意,有各种form of injections。还要注意,在这种观点下,setter injection可以看作是一种回调形式 - DI容器创建对象然后回调setter。有效地控制了控制流程。

    <强> 4。 AOP

    严格地说,AOP与之前的3点没什么关系。 seminal paper on AOP非常通用,提出了将各种来源编织在一起(可能用不同的语言表达)以生成工作软件的想法。

    我不会在AOP上进一步扩展。这里重要的是,依赖注入和AOP可以很好地协同工作,因为它使编织变得非常容易。如果使用IoC容器和依赖注入来抽象出对象的实例化,则可以在注入依赖项之前轻松地使用IoC容器编织方面。否则,这将需要特殊编译或特殊ClassLoader

    希望这有帮助。

答案 1 :(得分:10)

How to explain dependency injection to a 5-year-old?中很好地解释了依赖注入:

  

当你离开的时候   冰箱给自己,你可以   引起问题。你可能会离开   门开了,你可能会得到一些东西   妈妈或爸爸不要你   有。你甚至可能正在寻找   我们甚至没有的东西或者哪些东西   已过期。

     

你应该做的是说明一个   需要,“我需要喝点东西   午餐,“然后我们会确保你   坐下来时有所收获   吃。

AOP - 面向方面编程 - 基本上意味着您编写的源会根据位于ELSEWHERE的规则使用其他代码进行修改。这意味着您可以例如说“作为每个方法的第一行我想要'log.debug(”输入方法()“)'在一个中心位置,然后你用该规则编译的每个方法都会包含该行。“方面”是以其他方式查看代码的名称,而不仅仅是从第一个源行到最后一行。

控制反转基本上意味着你没有控制一切的中心代码(比如main()中的一个巨大的开关)但是有很多代码片段“以某种方式”被调用。维基百科讨论了这个主题:http://en.wikipedia.org/wiki/Inversion_of_control

答案 2 :(得分:1)

这三个都是不同的概念,但它们都能很好地协同工作,因此Spring应用程序通常会同时使用所有这些概念。我给你举个例子。

假设我们有一个可以做很多不同事情的Web应用程序。我们可以通过多种方式构建此应用程序,但一种方法是创建一个负责执行这些操作的类。我们需要从某个地方调用和创建这些类。一种选择是有一个大的主类创建这些服务中的一个,打开一个套接字,并在它们进来时将调用传递给这些服务。不幸的是,我们已经离开并创建了自己的神级,太多的逻辑,并且对我们程序中的所有内容如何运作有太多了解。如果我们改变了关于我们程序的任何内容,我们可能需要修改这个类。

此外,很难测试。如果它在实例化和直接调用其他类的情况下运行,我们就无法隔离测试任何类。单元测试变得越来越难写。

解决这个问题的一种方法是使用控制反转。我们说“好吧,这些都是服务类。谁将他们安置?不是我。”通常,每个人都定义一个接口,如LoginService或BillingService。该界面可能有多个实现,但您的应用并不关心。它只知道它可以要求某种服务或具有特定名称的服务,它会得到一些好的回报。

依赖注入允许我们将所有的litle碎片连接在一起。类具有可访问的字段,构造函数参数或setter方法,这些方法是对它们需要访问的其他组件的引用。这使得单元测试更容易。您可以创建受测试的对象,在其上抛出模拟或存根依赖关系,然后单独测试对象的行为是否正确。

现在,我们真正的应用程序是一个复杂的混乱片段,所有这些都需要连接在一起。有很多方法可以实现这一点,包括允许应用程序进行猜测(“这个类需要一个UserService,还有一个我负责实现UserService的其他类”)或者仔细解释它们如何在XML中连接在一起或者Java。 Spring的核心是一个服务,负责将这些类连接在一起。

现在我们到达AOP。让我们说,我们所有这些类都以精细的方式相互连接。我们可能希望以非常通用的方式描述一些跨领域的问题。例如,您可能希望在调用任何服务时启动数据库事务,并且只要服务不引发异常,就提交该事务。事实证明,Spring在执行这样的任务方面处于独特的地位。 Spring可以动态创建代理类,实现类所需的任何接口,并且可以将您的类包装在其代理中。现在,IoC和依赖注入当然不是进行面向方面编程所必需的,但它是一种非常方便的方法来实现它。

答案 3 :(得分:1)

让我告诉你关于AOP的一些消息,希望它让它更容易理解。 AOP的基本原则是找到返回的常见任务/方面 代码中的许多地方并不属于代码的概念业务。例如 写入以登录任何函数的每个入口,或者创建对象时包装它,或者在调用特定函数时向管理员发送电子邮件。 因此,代替程序员将处理这些非businuss方面,我们从他们和 我们管理现场的这些方面。 那一条AOP的所有基础......

答案 4 :(得分:1)

Spring in Action的简单比较:

  

DI可以帮助您解耦您的应用程序   相互之间的对象,AOP可以帮助您解决交叉问题   他们影响的对象。

答案 5 :(得分:1)

中很好地解释了依赖注入和控制反转之间的区别

http://martinfowler.com/articles/dipInTheWild.html

(“你的意思是依赖倒置,对吗?”部分)

摘要:

  

DI是关于一个对象如何获得依赖关系的。当一个依赖   在外部提供,然后系统使用DI。

     

IoC是关于谁发起呼叫的。如果您的代码发起了呼叫,   如果容器/系统/库回调代码,那么它不是IoC   你提供它,是IoC。