@JFinal 波总在 JFinal 4.8 发布新闻的评论 中给出了下面的表述:

我有点吃惊, 没想到 Java 界的大佬对这两个概念有和我完全不一致的认识. 所以写下这篇博客, 并借此机会重新学习一下 IoC 和 AOP, 确保自己对这两个后端开发非常重要的概念不会有太过偏差的理解

1. IoC

IoC 是 Inversion of Control 的缩写, 中文意思是控制反转. 维基百科对 IoC 开宗明义的定位为:

维基文中对此有详细的阐述, 大家可以自行前往维基百科 Inversion_of_control 词条查看, 我就不一一 Copy/Paste 了. 这里帮大家检出几个关键地方捋一捋:

  1. IoC 是编程原则 - 不是特定的产品, 不是具体实现方式, 当然也和具体编程语言无关
  2. 在传统编程范式中, 程序调用可重用的库
  3. 在 IoC 原则下, 程序接受通用框架的调用控制 - 框架调用程序代码
  4. 与 IoC 原则相关的概念包括:
    • 软件框架
    • 回调
    • 调度器
    • 事件循环
    • 依赖注入
    • 设计模式中的模板方法
  5. IoC 的设计目的包括:
    • 将执行任务和任务实现解耦
    • 让模块专注于设计任务
    • 模块仅依赖于设计契约而无需关注其他系统如何工作
    • 避免模块替换时的副作用

到这里我们可以比较清楚地得出下面的结论了:

那为什么波总会说 "IOC 本质是为了实现 AOP" 呢? 我姑且胡乱猜测一下, 波总想说的有可能是 "DI 本质是为了实现 AOP". 下面我们来探讨一下 DI, 这个和 IoC 以及 AOP 都有关系的概念.

2. DI

DI - Dependency Injection, 中文叫依赖注入, 在维基百科中的定义为:

特别地, 维基百科中的 DI 词条给出了下面的描述:

上面在对 DI 的描述中引入了另一个概念: SoC (Separation of Concern), 中文名关注点分离. 这是计算机科学中的一条设计原则, 简单地说就是将计算机程序划分为独立的单元, 每个单元解决一个可分离的关注点. 这个概念和封装 (Encapsulation) 非常接近, 可以说封装是对 SoC 设计原则的一种具体实现. 而 DI 则被描述为在构造和使用对象上实现 SoC 这个设计原则.

从上面的表述我们可以得到第二条结论:

那 DI 或者 IoC 到底和 AOP 有没有关系, 我们先来看看 AOP 的定义

3. AOP

AOP - Aspect Oriented Programming 在维基百科中的定义为:

这里面有几个关键点:

  1. AOP 是一个编程范式. 听上去有点晦涩, 下面列举几个编程范式的例子可以帮助大家理解这个概念:
    • Imperative - 指令式, c, c++, Java
    • Declarative - 声明式, SQL, 各种 DSL, 比如 ANTLR 的语法文件
  2. AOP 的目的是通过分离横切关注点(Separation of cross-cutting concern) 来提高模块性.

这里的 Separation of cross-cutton conern 是不是有点耳熟? 回顾上面提到的 DI 描述中引入的 Separation of Concern, 两个概念字面相近, 但又不完全一致. AOP 关注的是切面, 而 DI 关注的是对象构造. 如果没有注意到这个异同处, 有可能将 DI (甚至 IoC) 和 AOP 的概念搅和到一起.

扩展讨论

无独有偶, 前段时间 drinkjava (@yong9981) 同学也和我就 AOP 以及 DI 的关系进行了比较深入的探讨, 话题包括:

  1. AOP 的实现是否必须有 DI 提供
  2. Web 框架是否必须提供通用 AOP 的实现
  3. 声明式事务是否必须采用 AOP 来提供

对这些话题感兴趣的朋友可以继续访问 谈谈 Act 的依赖注入 和 模板输出 - 回 drinkjava 同学的评论.

12-22 00:31