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