我试图了解AOP,依赖注入和控制SPRING相关概念的反转,但我很难理解它。
任何人都可以用简单的英语解释这个吗?
答案 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
:
在上面提供的示例中,如果使用容器实例化对象并自动注入构造函数中的依赖项(我们经常说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。