1. 什么是 AOP?

AOP(Aspect-Oriented Programming,面向方面编程),可以说是 OOP(Object-Oriented Programing,面向对象编程)的补充和完善。它能够将那些与业务无关,却为业务模块所共同调用的逻辑或责任(例如事务处理、日志管理、权限控制等)封装起来,便于减少系统的重复代码,降低模块间的耦合度,并有利于未来的可拓展性和可维护性。

AOP 的实现原理是动态代理,使用 AOP 之后我们可以把一些通用功能抽象出来,在需要用到的地方直接使用即可,这样大大简化了代码量。我们需要增加新功能时也方便,这样也提高了系统扩展性。日志功能、事务管理等等场景都用到了 AOP 。

2. AOP 的基本概念

Spring AOP - 图1

  1. 通知(Advice):就是我们想要的功能(如日志),用来声明方面组件 Aspect 到底需要处理哪些逻辑。
  2. 连接点(JoinPoint):目标对象 Target 上有很多地方可以被织入代码,能够被织入代码的地方统称为连接点 JoinPoint。Spring AOP 只支持方法连接点,和方法有关的前前后后都是连接点。
  3. 切入点(Pointcut):选择指定的方法进行织入,即用切点来筛选连接点,选中我们想要的那些方法。
  4. 切面(Aspect):切面是通知和切入点的结合。
  5. 目标(Target):程序当中已经开发好的用于处理业务逻辑的一个个 bean,也就是要被通知的对象。在 JDK 动态代理中,被织入的代理实例是原对象的代理对象;在 CGLib 动态代理中,被织入的代理实例是原对象的子类对象。
  6. 织入(Weaving):创建代理对象,把切面应用到代理对象上的过程。有三种方式,分别是编译时织入装载时织入运行时织入,Spring AOP 采用的是运行时织入。

    3. Spring AOP 的代理方式

    所谓动态代理,就是当想要给实现了某个接口的类中的方法加一些额外的处理时,比如说加日志、加事务等,可以给这个类创建一个代理,顾名思义就是创建一个新的类,这个类不仅包含原来类方法的功能,而且还在原来的基础上添加了额外处理的新功能。

    3.1 JDK 动态代理(目标对象存在接口)

  • Java 提供的动态代理技术,可以在运行时创建目标对象接口的实现类作为代理实例。所谓的代理就是对某个对象生成它的代理对象来代替这个对象,调用时调用代理对象,织入代码时也是直接织入到代理对象里。
  • Spring AOP 默认采用此种方式,在接口的代理实例中织入代码。

    3.2 CGLib 动态代理(目标对象不存在接口)

  • 采用底层的字节码技术,在运行时创建目标对象的子类作为代理实例。

  • 当目标对象不存在接口时,Spring AOP 会采用此种方式,在子类实例中织入代码。

    4. Spring AOP 中有哪些 Advice?

  1. 前置通知(Before advice):在某连接点之前执行的通知,但这个通知不能阻止连接点前的执行。
  2. 后置通知(After advice):当某连接点退出的时候执行的通知(不论是正常返回还是异常退出)。
  3. 返回后通知(After return advice):在某连接点正常完成后执行的通知,不包括抛出异常的情况。
  4. 环绕通知(Around advice):包围一个连接点的通知,类似 Web 中 Servlet规范中的 Filter 的 doFilter 方法。可以在方法的调用前后完成自定义的行为,也可以选择不执行。
  5. 抛出异常后通知(After throwing advice):在方法抛出异常退出时执行的通知。

    5. Spring AOP 和 AspectJ 的区别?

    AspectJ(编译期织入):
  • AspectJ 是语言级的实现,它扩展了 Java 语言,定义了 AOP 语法,相当于一门新的语言。
  • AspectJ 在编译期织入代码,它有一个专门的编译器,用来生成遵守 Java 字节码规范的 Class 文件。
  • 基于字节码操作。


Spring AOP(运行期织入):**

  • Spring AOP 使用纯 Java 实现,它不需要专门的编译过程,也不需要特殊的类加载器。
  • Spring AOP 在运行时通过代理的方式(JDK 动态代理或 CGLib 动态代理)织入代码,只支持方法类型的连接点(只能在方法上织入)。
  • 基于代理。