谈谈我对 IoC 和 AOP 的理解

Java基础

浏览数:15

2020-5-28

AD:资源代下载服务

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

IOC 本质是为了实现 AOP

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

1. IoC

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

In software engineeringinversion of control (IoC) is a programming principle

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

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

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

J1. IoC 的本质不是为了实现 AOP.

J2. 波总的 JFinal 已经实现了 IoC 原则. 因为应用写的代码总是被 JFinal 的代码调用, 这就是控制反转.

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

2. DI

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

In software engineering, dependency injection is a technique whereby one object supplies the dependencies of another object.

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

Passing the service to the client, rather than allowing a client to build or find the service, is the fundamental requirement of the pattern.

The intent behind dependency injection is to achieve Separation of Concerns of construction and use of objects. This can increase readability and code reuse.

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

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

J3. DI 也不是为了实现 AOP

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

3. AOP

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

In computing, aspect-oriented programming (AOP) is a programming paradigm that aims to increase modularity by allowing the separation of cross-cutting concerns.

这里面有几个关键点:

  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 同学的评论.

更新 – 2019-12-26

我不同意 @yong9981 对本文的评论, 并在这里做了反驳:

作者:开源老码农