浅谈 AOP
AOP
AOP 定义
Aspect Oriented Programming:面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术
Aspect 语义理解
- A way in which something can be viewed by the mind
- A characteristic or feature of something
个人认为应该将其理解为一种编程思想而不是具体技术,否则可能会很自然地将 AOP 与 Spring 绑定。
AOP 地位
OOP 的延续
函数式编程 的 变体范式
回顾 gcc 编译的四个阶段
预处理(Pre-Processing) -> 编译(Compling) -> 汇编(Assembling) -> 连接(Linking)
预处理:主要负责展开在源文件中定义的宏,并向其中插入#include语句所包含的内容
简单总结就是导包
编译:源程序 → 汇编程序
汇编:汇编程序 → 机器码
连接:将生成的目标文件和其所依赖的库文件进行连接,生成一个可执行文件
回顾完编译四个阶段以后,虽然 Java 是解释型语言,但是对于 AOP 的运行机制也有了更深的理解,预编译方式实现维护就相当于额外导包,初见预计这种方式需要额外的导包机制支持
运行期动态代理也很好理解,就是在运行阶段进行一些代理工作,显然相比于预编译阶段就更加“动态”,初见预计这种方式需要额外的运行环境支持,使用后发现其实貌似也没用上额外的环境支持,本质上还是用好 Java 的动态绑定
AOP 的作用
程序运行期间,不修改源码对已有方法进行增强
按照这种说法,个人认为异常捕获机制也算是比较原初的 AOP
好处
- 减少重复代码
抽离了通用性的辅助代码,使其可复用 - 提高开发效率
减少重复代码的衍生效果
业务流程与环境辅助分离,并行开发成为可能 - 方便维护
业务流程与环境辅助分离,互不影响,维护只需分别针对业务流程、环境辅助以及连接过程三方面进行
应用场景
日志记录、性能统计、安全控制、事务处理、异常处理
均体现了对于业务流程的环境辅助的性质
环境辅助的本质是监控、记录、处理
与之相关的还有环境支持的概念,环境支持就是运行环境,本质上是为业务流程提供的基础设施
AOP 底层实现
- 接口代理( JDK 动态代理)
- 子类代理( Cglib 子类代理)
无论是接口还是子类,都暗含了继承关系,为实现 AOP ,这种继承关系是必要的吗?初见感觉既然暗含继承关系,可能会与动态绑定机制有关,如果与动态绑定机制相关,这种继承关系就是必要的。但就目前的认知水平而言这种观点仅作为一种猜测
回顾 动态绑定机制
动态绑定机制:对象是存在继承关系的家族类子孙类的实例,调用对象中被重写的方法时,JVM从最子类开始依次寻找方法的实现,直到找到为止
简单来说就是,执行最“子”子类的实现方法
回顾 重写与重载的区别
本质上都是对同名方法进行改写
重写:不要求参数表不同,通过动态绑定机制决定执行哪个函数
重载:要求参数表不同,通过参数表匹配机制决定执行哪个函数
显然,由于重写依赖动态绑定机制实现,其依赖于继承关系,只能对父类与子类范围内的同名函数进行改写,而重载就可对任意同名函数进行改写
AOP 术语
Target:目标对象
待增强的目标类
Jointpoint:连接点
类或代码段中具有边界性质的点
Pointcut:切点
一系列连接点的集合
Introduction:引介
特殊增强,本质上是为类添加的一些属性和方法,让A接口实现类能实现的B接口的功能,以获得原来没有的能力
违背单一职责原则,慎用
Aspect:切面
由切点和引介组成,同时包含横切逻辑和连接点的定义,简单地说,切面告诉目标对象如何增强和在哪增强
Weaving:织入
将增强添加到目标类具体连接点上的过程
- 编译器织入:要求使用特殊的 Java 编译器
- 类装载期织入:要求使用特殊的类装载器
- 动态织入
运行期为目标类添加增强子类
Advice:通知
织入到目标类连接点上的一段程序代码
Proxy:代理
织入增强后产出的结果类,即融合了原类和增强逻辑的代理类
AOP 总结
总的来说,AOP 作为一种技术,其目标是实现运行期内源代码无关的程序增强
在细粒度视角看,这种增强就是一种纯增强,在粗粒度视角看,这种增强也可作为一种引入层(即引入统一管理)的方法
何时增强?
虽然要求是运行期期间增强,但是其增强介入时间可以是运行期前的编译阶段、类装载阶段或运行期期间(显然,运行期期间还有一个更细分的时间节点,即代增强目标使用前)
如何增强?
AOP 的实现机制也不复杂,由于其源代码无关的限制,要增强只能通过类似于外置装甲(ガンダム)的形式进行增强
要实现这种外置装甲的机制,就带来以下问题
- 在哪连接?
连接点、切点 - 怎么连接?
织入 - 连接什么?
引介、通知
连接的结果是获得代理类
AOP工作流程
从上图看,前置 Advice 与待增强函数的执行过程无关(毕竟先于待增强函数执行),后置 Advice 的执行过程与目标函数的执行过程相关
AOP 增强结果
Spring AOP
Spring AOP
Spring AOP 是体现 AOP 编程思想的一种具体技术,体现 AOP 编程思想的具体技术除了 Spring AOP 以外还有 AspectJ
如何定义具体技术?
此处先不做正经思考,姑且下个简单定义:具体技术就是在抽象思想的指导下形成的一种可用工具
思想本身是不能直接拿来用的,而技术可用直接用
思想是一种美好的理想愿景,技术是考虑现实限制后的实现手段
限制本身也体现了扩展,或者说从某种程度上看扩展本身服务于某些限制
思想指导技术,技术体现思想
Spring AOP 的实现限制
限制是某种程度的扩展,当然实现过程也允许一般意义上的扩展
何时连接?
Spring 采用动态代理织入
补充:AspectJ 采用编译期织入和类装载期织入
在哪连接?
Spring 仅支持方法的连接点
意思就是说不能用于增强类
这就导致 Spring 仅能在方法调用前后以及方法抛出异常这些执行点进行织入
怎么连接?
Spring AOP 是负责实施切面(连接点 + 连接物)的框架
连接什么?
Spring 中的通知包括 程序代码和连接点信息(方位)