IOC/DI
熟悉Spring框架的人应该都听说过 IOC(Inversion of Control,控制反转)和 DI(Dependency Injection,依赖注入)两个概念,这其实是面向对象的一种编程思想,本文主要谈谈对于它们的理解。
首先我们必须搞清楚这两个概念涉及的参与者都有谁?
一般有三方参与者:一是某个对象;另一个是 IOC/DI 容器;还有一个是某个对象的外部资源。
详细解释一下这三个参与者,某个对象指的就是任意的、普通的Java对象;IOC/DI 容器简单点说就是指用来实现 IOC/DI 功能的一个框架程序;对象的外部资源指的就是对象需要的,但是是从对象外部获取的,都统称资源,比如:对象需要的其它对象、或者是对象需要的文件资源等等。
控制反转该怎么理解呢?
这里的控制主要是指控制对象的创建。为何叫反转呢? 反转是相对于正向而言的,那么什么算是正向的呢?考虑一下常规情况下的应用程序,如果要在A里面使用C,你会怎么做呢?当然是直接去创建C的对象,也就是说,是在A类中主动去获取所需要的外部资源C,这种情况被称为正向的。那么什么是反向呢?就是A类不再主动去获取C,而是被动等待,等待 IOC/DI 容器获取一个C的实例,然后反向的注入到A类中。
用图例来说明一下。
先看没有 IOC/DI 的时候,常规的A类使用C类的示意图。
当有了 IOC/DI 容器后,A类不再主动去创建C了。
而是被动等待,等待 IOC/DI 容器获取一个C的实例,然后反向的注入到A类中。
依赖注入该怎么理解呢?
因为对象需要的外部资源不会主动去创建了,所以就依赖 IOC/DI 容器把这个外部资源注入给它。
依赖注入和控制反转是同一概念吗?
根据上面的讲述,应该能看出来,依赖注入和控制反转是对同一件事情的不同描述,从某个方面讲,就是它们描述的角度不同。依赖注入是从应用程序的角度在描述,可以把依赖注入描述完整点:应用程序依赖容器创建并注入它所需要的外部资源;而控制反转是从容器的角度在描述,描述完整点:容器控制应用程序,由容器反向的向应用程序注入应用程序所需要的外部资源。
为什么需要IOC/DI,这样做有什么好处?
没有 IOC/DI 容器的情况下,对象需要的外部资源需要自己进行创建并初始化,这种对象与外部资源之间是紧密耦合的,不利于代码的维护与迭代,比如外部资源的创建方式发生变化,那么所有创建的地方都要修改代码(当然这个问题可以通过工厂模式来解决,工厂模式和 IOC/DI 的思想本来就是类似的,但 IOC/DI 应该算是工厂模式的一种升级版本,因为工厂模式下还需要对象主动从工厂去拉取资源,而且 IOC/DI 不仅支持代码的方式创建对象,还支持xml配置、注解等多种方式,更为灵活)。
有了 IOC/DI 容器,应用程序中的对象的创建、初始化和销毁都可以由容器去处理,有效地分离了对象和它所需要的外部资源,使得它们松散耦合,有利于功能复用,更重要的是使得程序的整个体系结构变得非常灵活。
IOC容器的技术剖析
IOC中最基本的技术就是“反射(Reflection)”编程,目前.Net C#、Java和PHP5等语言均支持,其中PHP5的技术书籍中,有时候也被翻译成“映射”。有关反射的概念和用法,大家应该都很清楚,通俗来讲就是根据给出的类名(字符串方式)来动态地生成对象。这种编程方式可以让对象在生成时才决定到底是哪一种对象。反射的应用是很广泛的,很多的成熟的框架,比如象Java中的Hibernate、Spring框架,.Net中 NHibernate、Spring.Net框架都是把“反射”做为最基本的技术手段。
反射技术其实很早就出现了,但一直被忽略,没有被进一步的利用。当时的反射编程方式相对于正常的对象生成方式要慢至少得10倍。现在的反射技术经过改良优化,已经非常成熟,反射方式生成对象和通常对象生成方式,速度已经相差不大了。