Spring AOP 原理

AOP 即面向切面编程(Aspect Oriented Programing),实际上是将一些通用的功能横向抽取出来:

  • 一方面,减少系统的重复代码
  • 另一方面,降低模块间的耦合度,比较好维护和扩展

Spring AOP 将应用分为核心关注点和横切关注点。业务处理流程为核心关注点,被业务所依赖的公共部分为横切关注点。横切关注点的特点是其行为经常发生在核心关注点多出,而多处操作基本相似,比如权限认证、日志、事务等。AOP 的核心思想是将核心关注点和横切关注点分离开来,以降低模块耦合度。

Spring AOP 的应用场景主要有:

  • 权限统一管理授权
  • 缓存统一维护
  • 数据懒加载
  • 资源池统一申请和管理
  • 统一事务管理

AOP 相关术语

术语 解释 描述
Joinpoint 连接点 所谓连接点是指那些被拦截到的点。在 Spring 中,这些点指的是方法,因为 Spring 只支持方法类型的连接点
Pointcut 切入点 所谓切入点是指我们要对哪些 Joinpoint 进行拦截的定义。
Advice 通知/增强 所谓通知是指拦截到 Joinpoint 之后要执行的具体操作。通知分为前置通知,后置通知,异常通知,最终通知,环绕通知(切面要完成的功能)
Introduction 引介 引介是一种特殊的通知。在不修改类代码的前提下,可以在运行期为类动态地添加一些方法或字段
Target 目标对象 代理的目标对象
Weaving 织入 是指把增强应用到目标对象来创建新的代理对象的过程。 有三种织入方式:Spring 采用动态代理织入,而 AspectJ 采用编译期织入类装载期织入
Proxy 代理 一个类被 AOP 织入增强后,就产生一个结果代理类
Aspect 切面 是切入点和通知(/引介)的结合

例如在 IUserDao 接口中:

1
2
3
4
5
6
public interface IUserDao {
void add();
void delete();
void update();
void search();
}
  • IUserDao 被增强的对象,就是 Target(目标对象)
  • add()、delete()、update() 和 search() 都是 JoinPoint(连接点)
  • 这里要对 add() 和 update() JoinPoint 进行拦截,则 add() 和 update() 就是 Pointcut(切入点)
  • Advice 指的是要增强的代码,也就是代码的增强
  • Weaving:指的是把增强(Advice)应用到目标对象(Target)创建新的代理对象的过程
  • Aspect:是切入点和通知的结合,在 add 或 update 方法上应用增强

AOP 底层原理

AOP 的底层原理是动态代理机制:

  • 类实现了接口,JDK 动态代理
  • 类未实现任何接口,Cglib 动态代理

AOP 的 5 种通知类型

  • 前置通知

    在连接点前面执行,前置通知不会影响连接点的执行,除非此处抛出异常。

  • 后置通知

    在连接点执行完成后执行,不管是正常执行完成,还是抛出异常,都会执行返回通知中的内容。

  • 成功通知

    在连接点正常执行完成后执行,如果连接点抛出异常,则不会执行。

  • 异常通知

    在连接点抛出异常后执行。

  • 环绕通知

    环绕通知围绕在连接点前后,比如一个方法调用的前后。这是最强大的通知类型,能在方法调用前后自定义一些操作。环绕通知还需要负责决定是继续处理连接点(调用ProceedingJoinPoint 的 proceed 方法)还是中断执行。

五种通知的执行顺序为:前置通知、环绕通知、成功通知/异常通知、后置通知。

Spring AOP & AspectJ AOP

  • 增强时机

    Spring AOP 是运行时增强;AspectJ 是编译时增强

  • 底层原理

    Spring AOP 基于代理;AspectJ 基于字节码操作 (Bytecode Manipulation)

  • 性能

    AspectJ 相比于 Spring AOP 功能更加强大,AspectJ 应该算的上是 Java 生态系统中最完整的 AOP 框架了。Spring AOP 相对来说更简单,并且 Spring AOP 已集成了 AspectJ,如果切面较少,那么两者性能差异不大,当切面较多时,最好选择 AspectJ ,它比 Spring AOP 快很多。