让我们首先定义一些核心的 AOP 概念和术语。这些术语并不是针对 Spring 的。不幸的是,AOP 的术语并不是特别直观。然而,如果 Spring 使用自己的术语,那就更令人困惑了。
- Aspect / 切面:
一个跨越多个类的关注点的模块化。事务管理是企业级 Java 应用程序中跨领域关注点的一个很好的例子。在 Spring AOP 中,各个切面是通过使用常规类(XML 风格)或用 @Aspect
注解的 常规类(@AspectJ 风格)来实现的。
- Join point / 连接点:
在程序执行过程中的一个点,例如一个方法的执行或一个异常的处理。在 Spring AOP 中,一个连接点总是代表一个方法的执行。
- Advice / 增强(通知):
一个切面在一个特定的连接点采取的行动。不同类型的增强包括 around(周围)、before(之前 )和 after(之后)这些类型在后面讲解。许多 AOP 框架,包括 Spring,都将增强建模为一个拦截器,并在连接点周围维护一个拦截器链。
- Pointcut / 切入点:
一个匹配连接点的谓词。Advice 与一个切入点表达式相关联,并在切入点匹配的任何连接点上运行(例如,执行一个具有特定名称的方法)。由切入点表达式匹配的连接点概念是 AOP 的核心,Spring 默认使用 AspectJ 的切入点表达式语言。
- Introduction / 引入:
代表一个类型声明额外的方法或字段。Spring AOP 允许你为任何 Advice 的对象引入新的接口(以及相应的实现)。例如,你可以使用引入来使一个 bean 实现 IsModified
接口,以简化缓存。(Introduction 在 AspectJ 社区中被称为类型间声明)。
- Target object / 目标对象:
被一个或多个切面所增强的对象。也被称为 「增强对象」。由于 Spring AOP 是通过使用运行时代理来实现的,这个对象总是一个被代理的对象。
- AOP proxy / AOP 代理:
一个由 AOP 框架创建的对象,以实现切面契约(增强方法执行等)。在 Spring 框架中,AOP 代理是一个 JDK 动态代理或 CGLIB 代理。
- Weaving / 编织:
将 切面 与其他应用程序类型或对象连接起来,以创建一个 增强对象。这可以在编译时(例如,使用 AspectJ 编译器)、加载时或运行时完成。Spring AOP 和其他纯 Java AOP 框架一样,在运行时进行编织。
Spring AOP 包括以下类型的增强(也称为通知):
- Before advice / 通知前:在连接点之前运行的通知,但没有能力阻止执行流进行到连接点(除非它抛出一个异常)。
- After returning advice / 通知后:在一个连接点正常完成后运行的通知(例如,如果一个方法执行完成后没有抛出一个异常,就会被执行)。
- After throwing advice / 抛出异常后的通知:如果方法因抛出异常而退出,这会运行这个通知
- After (finally) advice / 最终通知 :无论这个连接点以何种方式退出(正常或则异常退出)都将运行这个通知
- Around advice / 环绕通知:围绕一个连接点的通知,如方法调用。这是最强大的一种通知。围绕通知可以在方法调用之前和之后执行自定义行为。它还负责选择是否继续进行连接点或通过返回自己的返回值或抛出一个异常来缩短通知方法的执行。
环绕通知是最通用的一种通知。由于 Spring AOP 和 AspectJ 一样,提供了完整的通知类型,我们建议你使用功能最少的通知类型来实现所需的行为。例如,如果你只需要用一个方法的返回值来更新缓存,那么你最好实现一个 After returning advice,而不是一个 Around advice,尽管 Around advice 可以完成同样的事情。使用最具体的建议类型可以提供一个更简单的编程模型,减少错误的可能性。例如,你不需要在用于Around advice 的 JoinPoint 上调用 proceed()
方法,因此,你不能失败地调用它。
所有的 advice 参数都是静态类型的,因此你可以使用适当类型的 advice 参数(例如,方法执行的返回值的类型)而不是 Object 数组。
由 pointcuts 匹配的连接点的概念是 AOP 的关键,它区别于只提供拦截的旧技术。Pointcut 使 advice 能够独立于面向对象的层次结构而成为目标。例如,你可以将提供声明性事务管理的周围 advice 应用于跨越多个对象的一组方法(如服务层的所有业务操作)。