Spring实现AOP简单实例
AOP简介
AOP(Aspect-Oriented Programming)即 面向切面编程,与 OOP(Object-Oriented Programming,面向对象编程)相辅相成, 提供了与 OOP 不同的抽象软件结构视角。
在 OOP 中, 以类(class)为基本单元, 而 AOP 中的基本单元是 **Aspect(切面)**。
Aspect(切面)
Aspect 由 point cut 和 advice 组成,既包含了横切逻辑的定义,也包括了连接点的定义。
Spring AOP作为负责实施切面的框架,将切面所定义的横切逻辑织入到切面所指定的连接点中。
AOP将增强织入到目标对象的连接点上时,包含两个工作:1)如何通过 point cut 和 advice 定位到特定的 join point;2)如何在 advice 中编写切面代码。
可以简单地认为,使用 @Aspect 注解的类就是切面。
advice(增强)
advice(增强)是由 aspect 添加到特定的 join point (即满足 point cut 规则的 join point) 的一段代码。
Spring AOP会将 advice 模拟为一个拦截器(interceptor),并且在 join point 上维护多个 advice,进行层层拦截。
advice 的类型:
1)before advice,在 join point 前被执行的 advice。虽然 before advice 是在 join point 前被执行,但它并不能够阻止 join point 的执行,除非发生了异常(即在 before advice 代码中,不能人为地决定是否继续执行 join point 中的代码)。
2)after return advice,在一个 join point 正常返回后执行的 advice。
3)after throwing advice,在一个 join point 抛出异常后执行的 advice。
4)after(final) advice,无论一个 join point 是正常退出还是发生了异常,都会被执行的 advice。
5)around advice,在 join point 前和 joint point 退出后都执行的 advice,是最常用的 advice。
对应Spring注解:
连接点(join point)
连接点是程序运行中的一些时间点,例如一个方法的执行,或者是一个异常的处理。
在 Spring AOP 中,join point 总是方法的执行点。
切点(point cut)
切点匹配 join point 的谓词(a predicate that matches join points)。
Advice 是和特定的 point cut 关联的,并且在 point cut 相匹配的 join point 中执行。
在 Spring 中,所有的方法都可以认为是 join point。而 AOP 一般不在方法上添加 Advice, point cut 恰恰提供了一组规则(使用 AspectJ pointcut expression language 来描述) 来匹配 join point,给满足规则的 join point 添加 Advice。
Advice 在 join point 上执行,而 point cut 规定了哪些 join point 可以执行哪些 advice。
引入(introduction)
introduction是一个类型添加的额外方法或字段。
Spring AOP 允许为 目标对象 引入新的接口和对应的实现。
例如可以使用 introduction 来为一个 bean 实现 IsModified 接口,并以此来简化 caching 的实现。
目标对象(Target)
Target是织入 advice 的目标对象,也被称为 advised object。
因为 Spring AOP 使用运行代理的方式来实现 aspect,因此 adviced object 总是一个代理对象(proxied object)。
adviced object 指的不是原来的类,而是织入 advice 后所产生的代理类。
AOP proxy
一个类被 AOP 织入 advice,就会产生一个结果类,它是融合了原类和增强逻辑的代理类。
在 Spring AOP 中,一个 AOP 代理就是一个 JDK 动态代理对象或 CGLIB 代理对象。
Spring AOP 默认使用标准的 JDK 动态代理(dynamic proxy)技术来实现 AOP 代理,可以为任意的接口实现代理。
如果需要为一个类实现代理,可以使用 CGLIB 代理。当一个业务逻辑对象没有实现接口时,Spring AOP 默认使用 CGLIB 来作为 AOP 代理。
鉴于此,Spring AOP 建议基于接口编程,对接口进行 AOP 而不是类。
各代理类别比较:
织入(Weaving)
织入(Weaving)指将 aspect 和其他对象连接起来,并创建 adviced object 的过程。
根据不同的实现技术,AOP织入有三种方式:
1)编译器织入,要求有特殊的Java编译器;
2)类装载期织入,需要有特殊的类装载器;
3)动态代理织入,在运行期为目标类添加增强(Advice)生成子类的方式。
Spring 采用动态代理织入,而 AspectJ 采用编译器织入和类装载期织入。
aspect, join point, point cut, advice
join point:所有的接口;
point cut:切面编程的条件;
advice:满足切面编程条件的所有接口;
aspect:处理所有增加切面编程的接口;
引入依赖
1 | // https://mvnrepository.com/artifact/org.springframework/spring-context |
切面接口类:IBuy
1 | package com.demo; |
切面接口实现类:Boy
1 | package com.demo; |
切面接口实现类:Girl
1 | package com.demo; |
AOP配置类:AOPConfig
1 | package com.demo; |
切面处理类:BuyAspectJ
1 | package com.demo; |
切面测试类:AOPTest
1 | package com.demo; |
运行结果
1 | before ... |