在一个大型项目当中,由于代码的复杂度高,就产生了耦合度过高的问题,即类与类之间的依赖程度过高,如果此时一个类出现了bug或者业务上的需求,需要修改代码,那么其他的类也受到影响,导致大量的修改,造成可维护性差的问题。为了降低软件设计中的耦合度,更好的处理类之间的依赖关系,因此出现了 IOC (控制反转) 这种设计模式。
IOC 思想
把通过new产生对象的这种方式,改变通过把类的定义以及属性和方法编写到.xml配置文件中,在运行的时候,Java会利用”反射”的方式,在外部根据写好的.xml配置文件中的类定义,生成相应的对象—这就把源码和生成对象隔离了。
所谓反射的方式,也就是根据配置文件中的全类名,来获得该类的对象。
以上仅仅是在外部产生了对象,为了业务的需求,程序不可能没有依赖关系。我们也会在.xml配置文件中编写类与类之间的关系,比如说Service类引用了Dao类的对象。但值得注意的是,容器(比如Spring)会自动把生成的对象根据编写好的依赖关系,注入到软件中去,即把实例化的Dao类对象注入到Service类下的引用中,从而产生依赖关系。通过这种方式产生依赖关系,大大降低了源代码的耦合度。因为需要改动的时候,只要改动.xml配置文件即可。
这就是”依赖注入”,把外部生成的实例化对象注入到源码中该对象的引用中去,使程序之间产生依赖关系。这是IOC的一个重要的实现方式。
以上所说的是IOC完成了底层部分的工作。IOC实际上所有的工作包括: 创建对象,管理对象(通过依赖注入),整合对象,配置对象以及管理对象的生命周期。
理解 IOC 主要是通过一下 2 点:
- 谁控制谁?IoC 容器控制了对象;控制什么?控制了外部资源获取。
- 传统应用程序是由我们自己在对象中主动控制去直接获取依赖对象,是正转;而反转则是由容器帮我们查找及注入依赖对象,对象只是被动的接受依赖对象。依赖对象的获取被反转了。
理解DI的关键是:“谁依赖谁,为什么需要依赖,谁注入谁,注入了什么”:
- 谁依赖于谁:应用程序依赖于IoC容器;
- 为什么需要依赖:应用程序需要IoC容器来提供对象需要的外部资源;
- 谁注入谁: IoC 容器注入应用程序某个对象,应用程序依赖的对象;
- 注入了什么:注入某个对象所需要的外部资源(包括对象、资源、常量数据)。
IoC 和 DI 是同一个概念的不同角度描述,相对 IoC 而言,依赖注入明确描述了被注入对象依赖 IoC 容器配置依赖对象。
示例
传统程序设计都是通过new主动去创建相关对象然后再组合起来:

用户类
1 | public class User { |
用户业务类
1 | public class UserService { |
客户端
1 | public class Client { |
当有了容器后,在客户端类中不再主动去创建这些对象了(由IOC类完成)

IOC 类
1 | public class IOC { |
客户端
1 | public class Client { |