IoC 和 AOP 偏向于理论化, 在 Spring 之前就已经存在了。Spring 在技术层面把这两个层面做了非常好的实现。
IoC
什么是 IoC
IoC的全称是 Inversion Of Control 即控制反转与反转控制的意思。主要描述的是 Java 开发领域对象的创建和管理的问题。
传统的开发方式,比如类 A 依赖于 类 B,往往会在类 A 中 new 一个 B 的对象。但是在 IoC 下,我们不需要自己去 new 一个 B 的对象了,而是由 IoC 容器(Spring 框架)去帮助我们实例化这样一个对象并且管理它,我们从 IoC 容器中获取即可。
为什么叫控制反转
首先我把“控制反转”这个词拆解成两个词,一个是控制,另一个是反转。
控制:指的是对象创建的权力(实例化、管理)
反转:控制权交给了外部环境了(交给了 Spring 框架和 IoC 容器)
在没有 IoC 容器下,我们如何处理依赖关系的?如下图:
在由 IoC 容器的情况下,我们如何处理依赖关系的?如下图:
IoC 解决了什么问题
在上一篇中,我们说到 IoC 解决的是对象之间的耦合问题。
那么如何理解这句话呢?
我们知道 Java 代码其实是分层开发的,这里就以 service 层和 dao 层之间的调用举例:
假设 Dao 层,有一个 UserDao 及其实现类:
- 接口:UserDao
- 实现类:UserDaoImpl
假设 Service 层,有两个 Service (如下)都需要调用 Dao 层的 UserDao
- 接口:UserService、OrderService
- 实现类:UserServiceImpl、OrderServiceImpl
此时如果 UserDao 新增加了一个实现类 UserDaoNewImpl,而 UserService 需要用到 UserDaoNewImpl,此时就需要修改 Service 层相关的代码,此种 Service 和 Dao 耦合度太高,一个发生变化,另一个必须得发生变化,如果方法多的情况下,会很麻烦。
有了 AOP 思想后,只需要声明需要使用得 Dao 层接口,这样就变成了面向接口开发了,具体的实现类由 AOP 动态代理去实现。
DI
DI 的全称是 Dependency Injection 依赖注入的意思。
什么是 DI
IoC 和 DI 其实描述的是同一件事,只不过站在了不同的角度去描述了对象实例化以及依赖关系的维护。
IoC 是站在对象的角度:将对象的实例化及管理的权力交给了容器(反转给了容器)。
DI 是站在容器的角度:容器会把对象依赖的其它对象注入进去(比如:A 对象在实例化的过程中声明了 B 对象的一个属性,那么容器就会把 B 对象注入给 A)。
所以这就是 IoC 和 DI 的区别。
AOP
AOP 全称是 Aspect Oriented Programming 即面向切面编程/面向方面编程的意思。
什么是 AOP
说到 AOP ,我们必须得从 OOP 说起,我们可以把 AOP 看成是 OOP 的一个延续。
我们知道 OOP 有三大特征,分别是:封装、继承和多态。
OOP 其实是一种垂直继承体系,如下图:
OOP 编程思想可以解决大部分的重复代码问题,但是有些情况是处理不了的,比如:在 Animal 中的多个方法中相同的位置上出现了重复代码(日志、性能监控、事务等),OOP 就解决不了。在这里我们需要提到一个词:横切逻辑代码。
横切逻辑代码
横切逻辑代码:在多个纵向(顺序)流程中出现的相同子流程代码,我们称之为横切逻辑代码。
横切逻辑代码的使用场景:一般都是事务控制、权限校验、日志打印等。
横切逻辑代码本身存在什么问题:
- 代码重复
- 横切逻辑代码与业务代码混杂在一起,代码臃肿,不方便维护
AOP 的出现就可以解决这种问题。但是代码拆分容易,那么在不改变原有业务逻辑的情况下,如何做到悄无声息的把横切逻辑代码应用到原有的业务逻辑中,达到和原来一样的效果,这个是很困难的。
所以 AOP 解决的问题是:在不改变原有业务逻辑的情况下,增强横切逻辑代码,从根本上进行解耦,避免恒切逻辑代码重复。
什么是面向切面编程
切:指的是横切逻辑,原有的业务逻辑我们不能动,只能操作横切逻辑代码,所以是面向横切逻辑。
面:横切逻辑代码往往是要影响很多个方法的,每一个方法如同一个点,多个点构成一个面,这就是面的概念了。