AOP一般概念理解,非特定语言

10 阅读4分钟

AOP基本概念

AOP(Aspect-Oriented Programming),即“面向切面编程”。

AOP是什么

简单通俗地来说:AOP(面向切面编程)是一种:把“与核心业务无关、但到处都需要的逻辑”从业务代码中分离出来,并在合适的时机自动执行的编程思想

——AOP是一种编程思想

AOP一般的应用场景:日志、权限校验、事务、监控、缓存、异常处理……

它们的共同特征:

  1. 横跨大量业务逻辑
  2. 实现方式高度重复
  3. 和业务目标本身无关

这类问题叫:横切关注点(Cross-Cutting Concerns),而AOP 的目的只有一个:让这些“横着切进来的逻辑”不再污染业务代码

AOP的重要基本概念

切面(Aspect)

一组横切逻辑的集合

切面的本质就是:规则的集合。它包含“在哪个地方 + 什么时候 + 要做什么”,例如:在所有网络请求接口 → 调用前 → 校验权限。

切面是对“要做什么事情”的抽象(集合)。

连接点(Join Point)

程序执行过程中,天然存在的、可以被拦截的位置

常见连接点(跨语言):

  • 函数 / 方法调用
  • 函数返回
  • 抛异常
  • 对象创建
  • 属性访问(部分语言支持)

需要强调:“连接点”的概念虽然可能由AOP提出,但是连接点的存在和AOP没有任何关系,因为连接点是程序执行时天然存在的

连接点(Join Point)是一个在执行AOP功能中“通知(Advice)”的基础依据。正是“连接点”的天然存在,让AOP可以“在什么地方、什么时候”执行通知

切点(Pointcut)

对连接点( Join Point) 的筛选规则

切点(Pointcut)是匹配(筛选)连接点(Join Point)的判断规则(谓词),一般表现为要执行通知(Advice)的目标方法/函数

如:所有 public 方法、所有 controller 层函数、标记了某个注解 / 装饰器的函数。

切点(Pointcut)明确地告诉AOP“在什么地方”执行通知

通知(Advice)

在连接点上执行的具体逻辑和操作

常见类型(逻辑意义):

  • Before:之前
  • After:之后
  • AfterThrowing:出错时
  • Around:包住整个执行过程

通知(Advice)有两个作用:1.“什么时候做”;2.“做什么”

如上所述,Before、After、AfterThrowing、Around指明了在连接点执行前、执行后、执行出错(异常)时、整个执行过程(执行前、执行中、执行后)执行具体的操作。

织入(Weaving)

把切面(Aspect)逻辑真正整合进程序执行流程的过程

它不是“定义”,而是真正发生时的动作,即如何在程序运行时真正地执行切面中的代码,将切面“织入”到目标切点的位置。

织入可以发生在:

  • 编译期
  • 加载期
  • 运行期

织入(Weaving)由具体的AOP实现框架(Framework)(如Java的AsceptJ)采用具体语言能力(如Java的动态代理 / CGLIB)完成。

AOP的通用实现原理(跨语言视角)

第一:定义“可拦截点”(连接点)

任何语言,只要满足下面之一,就具备 AOP 的可能性

  • 可以拦截函数调用
  • 可以改写调用流程
  • 可以包裹原始逻辑

抽象表示:

原始执行流程:
call(target)

第二:定义“增强逻辑”(通知)

把横切逻辑抽象为函数:

before()
after()
onError()

这些逻辑 不关心业务细节

第三:建立“匹配规则”(切点)

需要一个规则系统:

if (this execution matches rule) {
    apply advice
}

这就是切点(Pointcut)的本质:一个“是否增强(通知)”的判定器

第四(核心):改变执行流程

这是 AOP 的技术核心

把原执行:

result = target()

变成:

before()
try {
    result = target()
    after()
} catch (e) {
    onError(e)
}

或者(Around):

result = advice(() -> target())

所有 AOP,最终都会退化成“函数包函数”

第五:选择织入时机

这是实现差异,而不是思想差异:

  1. 编译期

    • 修改中间代码 / 字节码 / AST

    • 代表:AspectJ、某些编译器插件

  2. 加载期

    • 模块加载时注入
    • 代表:字节码增强、ClassLoader Hook
  3. 运行期(最通用)

    • 代理对象
    • 装饰器
    • 高阶函数

具体编程语言举例:

语言技术
Java动态代理 / CGLIB
Python装饰器
JS函数包装 / Proxy
Gomiddleware
C#Castle DynamicProxy

一个“语言无关”的 AOP 伪代码

function weave(target, advice):
    return function(...args):
        advice.before()
        try:
            result = target(...args)
            advice.after()
            return result
        catch e:
            advice.onError(e)
            throw e

AOP本质总结

  1. AOP 不是某种语法,AOP 是一种“组织代码的方式”
  2. AOP 的核心不是“切面”,核心是:控制执行流程
  3. AOP 的终极抽象:AOP = 可拦截执行点(连接点) + 可插拔行为(通知) + 自动织入机制(织入)