Spring的IOC原理(通俗易懂)

  1. IoC理论的背景

咱们都知道,在采用面向对象方法设计的软件系统中,它的底层实现都是由Ñ个对象组成的,全部的对象经过彼此的合做,最终实现系统的业务逻辑。编程

若是咱们打开机械式手表的后盖,就会看到与上面相似的情形,各个齿轮分别带动时针,分针和秒针顺时针旋转,从而在表盘上产生正确的时间。图1中描述的就是这样的一个齿轮组,它拥有多个独立的齿轮,这些齿轮相互啮合在一块儿,协同工做,共同完成某项任务。咱们能够看到,在这样的齿轮组中,若是有一个齿轮出了问题,就可能会影响到整个齿轮组的正常运转。架构

齿轮组中齿轮之间的啮合关系,与软件系统中对象之间的耦合关系很是类似。对象之间的耦合关系是没法避免的,也是必要的,这是协同工做的基础。如今,伴随着工业级应用的规模愈来愈庞大,对象之间的依赖关系也愈来愈复杂,常常会出现对象之间的多重依赖性关系,所以,架构师和设计师对于系统的分析和设计,将面临更大的挑战。对象之间耦合度太高的系统,必然会出现牵一发而动全身的情形。框架

耦合关系不只会出如今对象与对象之间,也会出如今软件系统的各模块之间,以及软件系统和硬件系统之间。如何下降系统之间,模块之间和对象之间的耦合度,是软件工程永远追求的目标之一。为了解决对象之间的耦合度太高的问题,软件专家Michael Mattson提出了IOC理论,用来实现对象之间的“解耦”,目前这个理论已经被成功地应用到实践当中,不少的J2EE项目均采用了国际奥委会框架产品春季。编程语言

2.什么是控制反转(IoC) IOC是Inversion of Control的缩写,多数书籍翻译成“控制反转”,还有些书籍翻译成为“控制反向”或者“控制倒置”。 1996年,Michael Mattson在一篇有关探讨面向对象框架的文章中,首先提出了IOC这个概念。对于面向对象设计及编程的基本思想,前面咱们已经讲了不少了,再也不赘述,简单来讲就是把复杂系统分解成相互做用合做的对象,这些对象类经过封装之后,内部实现对外部是透明的,从而下降了解决问题的复杂度,并且能够灵活地被重用和扩展.IOC理论提出的观点大致是这样的:借助于“第三方”实现具备依赖关系的对象之间的,以下图:单元测试

你们看到了吧,因为引进了中间位置的“第三方”,也就是IOC容器,使得A,B,C,d这4个对象没有了耦合关系,齿轮之间的传动所有依靠“第三方”了,所有对象的控制权所有上缴给“第三方” IOC容器,因此,IOC容器成了整个系统的关键核心,它起到了一种相似“粘合剂”的做用,把系统中的全部对象粘合在一块儿发挥做用,若是没有这个“粘合剂”,对象与对象之间会彼此失去联系,这就是有人把IOC容器比喻成“粘合剂”的由来。学习

咱们再来作个试验:把上图中间的IOC容器拿掉,而后再来看看这套系统:测试

咱们如今看到的画面,就是咱们要实现整个系统所须要完成的所有内容。这时候,A,B,C,d这4个对象之间已经没有了耦合关系,彼此毫无联系,这样的话,当你在实现阿的时候,根本无须再去考虑B,C和d了,对象之间的依赖关系已经下降到了最低程度。因此,若是真能实现IOC容器,对于系统开发而言,这将是一件多么美好的事情,参与开发的每一成员只要实现本身的类就能够了,跟别人没有任何关系!优化

咱们再来看看,控制反转(IOC)到底为何要起这么个名字咱们来对比一下?网站

软件系统在没有引入IOC容器以前,如图1所示,对象甲依赖于对象B,那么对象阿在初始化或者运行到某一点的时候,本身必须主动去建立对象乙或者使用已经建立的对象B.不管是建立仍是使用对象B,控制权都在本身手上。 软件系统在引入IOC容器以后,这种情形就彻底改变了,如图3所示,因为IOC容器的加入,对象甲与对象乙之间失去了直接联系,因此,当对象甲运行到须要对象乙的时候,IOC容器会主动建立一个对象乙注入到对象甲须要的地方。ui

经过先后的对比,咱们不难看出来:对象甲得到依赖对象乙的过程,由主动行为变为了被动行为,控制权颠倒过来了,这就是“控制反转”这个名称的由来。

  1. IOC的别名:依赖注入(DI) 2004年,Martin Fowler探讨了同一个问题,既然IOC是控制反转,那么究竟是“哪些方面的控制被反转了呢?”,通过详细地分析和论证后,他得出了答案:“得到依赖对象的过程被反转了”控制被反转以后,得到依赖对象的过程由自身管理IOC容器主动注入因而,他给“控制反转“取了一个更合适的名字叫作”依赖注入(Dependency Injection)“。他的这个答案,实际上给出了实现IOC的方法:注入。所谓依赖注入,就是由IOC容器在运行期间,动态地将某种依赖关系注入到对象之中。

因此,依赖注入(DI)和控制反转(IOC)是从不一样的角度的描述的同一件事情,指就是经过引入IOC容器,利用依赖关系注入的方式,实现对象之间的解耦。 咱们举一个生活中的例子,来帮助理解依赖注入的过程。你们对USB接口和USB设备应该都很熟悉吧,USB为咱们使用电脑提供了很大的方便,如今有不少的外部设备都支持USB接口。

如今,咱们利用电脑主机和USB接口来实现一个任务:从外部USB设备读取一个文件。

电脑主机读取文件的时候,它一点也不会关心USB接口上链接的是什么外部设备,并且它确实也无须知道。它的任务就是读取USB接口,挂接的外部设备只要符合USB接口标准便可。因此,若是我给电脑主机链接上一个U盘,那么主机就从U盘上读取文件;若是我给电脑主机链接上一个外置硬盘,那么电脑主机就从外置硬盘上读取文件。挂接外部设备的权力由我做主,即控制权归我,至于USB接口挂接的是什么设备,电脑主机是决定不了,它只能被动的接受。电脑主机须要外部设备的时候,根本不用它告诉我,我就会主动帮它挂上它想要的外部设备,你看个人服务是多么的到位。这就是咱们生活中常见的一个依赖注入的例子。在这个过程当中,我就起到了IOC容器的做用。

经过这个例子,依赖注入的思路已经很是清楚:当电脑主机读取文件的时候,我就把它所要依赖的外部设备,帮他挂接上。整个外部设备注入的过程和一个被依赖的对象在系统运行时被注入另一个对象内部的过程彻底同样。

咱们把依赖注入应用到软件系统中,再来描述一下这个过程:

对象A依赖于对象B,当对象 A须要用到对象B的时候,IOC容器就会当即建立一个对象B送给对象A。IOC容器就是一个对象制造工厂,你须要什么,它会给你送去,你直接使用就好了,而不再用去关心你所用的东西是如何制成的,也不用关心最后是怎么被销毁的,这一切所有由IOC容器包办。

在传统的实现中,由程序内部代码来控制组件之间的关系。咱们常用new关键字来实现两个组件之间关系的组合,这种实现方式会形成组件之间耦合。IOC很好地解决了该问题,它将实现组件间关系从程序内部提到外部容器,也就是说由容器在运行期将组件间的某种依赖关系动态注入组件中。

  1. IOC为咱们带来了什么好处

咱们仍是从USB的例子提及,使用USB外部设备比使用内置硬盘,到底带来什么好处? 第1、USB设备做为电脑主机的外部设备,在插入主机以前,与电脑主机没有任何的关系,只有被咱们链接在一块儿以后,二者才发生联系,具备相关性。因此,不管二者中的任何一方出现什么的问题,都不会影响另外一方的运行。这种特性体如今软件工程中,就是可维护性比较好,很是便于进行单元测试,便于调试程序和诊断故障。代码中的每个Class均可以单独测试,彼此之间互不影响,只要保证自身的功能无误便可,这就是组件之间低耦合或者无耦合带来的好处。 第2、USB设备和电脑主机的之间无关性,还带来了另一个好处,生产USB设备的厂商和生产电脑主机的厂商彻底能够是互不相干的人,各干各事,他们之间惟一须要遵照的就是USB接口标准。这种特性体如今软件开发过程当中,好处但是太大了。每一个开发团队的成员都只须要关心实现自身的业务逻辑,彻底不用去关心其它的人工做进展,由于你的任务跟别人没有任何关系,你的任务能够单独测试,你的任务也不用依赖于别人的组件,不再用扯不清责任了。因此,在一个大中型项目中,团队成员分工明确、责任明晰,很容易将一个大的任务划分为细小的任务,开发效率和产品质量必将获得大幅度的提升。 第3、同一个USB外部设备能够插接到任何支持USB的设备,能够插接到电脑主机,也能够插接到DV机,USB外部设备能够被反复利用。在软件工程中,这种特性就是可复用性好,咱们能够把具备广泛性的经常使用组件独立出来,反复利用到项目中的其它部分,或者是其它项目,固然这也是面向对象的基本特征。显然,IOC不只更好地贯彻了这个原则,提升了模块的可复用性。符合接口标准的实现,均可以插接到支持此标准的模块中。 第4、同USB外部设备同样,模块具备热插拔特性。IOC生成对象的方式转为外置方式,也就是把对象生成放在配置文件里进行定义,这样,当咱们更换一个实现子类将会变得很简单,只要修改配置文件就能够了,彻底具备热插拨的特性。 以上几点好处,难道还不足以打动咱们,让咱们在项目开发过程当中使用IOC框架吗?

  1. IOC容器的技术剖析

IOC中最基本的技术就是“反射(Reflection)”编程,目前.Net C#、Java和PHP5等语言均支持,其中PHP5的技术书籍中,有时候也被翻译成“映射”。有关反射的概念和用法,你们应该都很清楚,通俗来说就是根据给出的类名(字符串方式)来动态地生成对象。这种编程方式可让对象在生成时才决定究竟是哪种对象。反射的应用是很普遍的,不少的成熟的框架,好比象Java中的Hibernate、Spring框架,.Net中 NHibernate、Spring.Net框架都是把“反射”作为最基本的技术手段。 反射技术其实很早就出现了,但一直被忽略,没有被进一步的利用。当时的反射编程方式相对于正常的对象生成方式要慢至少得10倍。如今的反射技术通过改良优化,已经很是成熟,反射方式生成对象和一般对象生成方式,速度已经相差不大了,大约为1-2倍的差距。

咱们能够把IOC容器的工做模式看作是工厂模式的升华,能够把IOC容器看做是一个工厂,这个工厂里要生产的对象都在配置文件中给出定义,而后利用编程语言的的反射编程,根据配置文件中给出的类名生成相应的对象。从实现来看,IOC是把之前在工厂方法里写死的对象生成代码,改变为由配置文件来定义,也就是把工厂和对象生成这二者独立分隔开来,目的就是提升灵活性和可维护性。

  1. IOC容器的一些产品

Sun ONE技术体系下的IOC容器有:轻量级的有Spring、Guice、Pico Container、Avalon、HiveMind;重量级的有EJB;不轻不重的有JBoss,Jdon等等。Spring框架做为Java开发中SSH(Struts、Spring、Hibernate)三剑客之一,大中小项目中都有使用,很是成熟,应用普遍,EJB在关键性的工业级项目中也被使用,好比某些电信业务。 .Net技术体系下的IOC容器有:Spring.Net、Castle等等。Spring.Net是从Java的Spring移植过来的IOC容器,Castle的IOC容器就是Windsor部分。它们均是轻量级的框架,比较成熟,其中Spring.Net已经被逐渐应用于各类项目中。

  1. 使用IOC框架应该注意什么

使用IOC框架产品可以给咱们的开发过程带来很大的好处,可是也要充分认识引入IOC框架的缺点,作到心中有数,杜绝滥用框架。 第1、软件系统中因为引入了第三方IOC容器,生成对象的步骤变得有些复杂,原本是二者之间的事情,又凭空多出一道手续,因此,咱们在刚开始使用IOC框架的时候,会感受系统变得不太直观。因此,引入了一个全新的框架,就会增长团队成员学习和认识的培训成本,而且在之后的运行维护中,还得让新加入者具有一样的知识体系。 第2、因为IOC容器生成对象是经过反射方式,在运行效率上有必定的损耗。若是你要追求运行效率的话,就必须对此进行权衡。 第3、具体到IOC框架产品(好比:Spring)来说,须要进行大量的配制工做,比较繁琐,对于一些小的项目而言,客观上也可能加大一些工做成本。 第4、IOC框架产品自己的成熟度须要进行评估,若是引入一个不成熟的IOC框架产品,那么会影响到整个项目,因此这也是一个隐性的风险。 咱们大致能够得出这样的结论:一些工做量不大的项目或者产品,不太适合使用IOC框架产品。另外,若是团队成员的知识能力欠缺,对于IOC框架产品缺少深刻的理解,也不要贸然引入。最后,特别强调运行效率的项目或者产品,也不太适合引入IOC框架产品,象WEB2.0网站就是这种状况。

相关文章
相关标签/搜索