Spring AOP
面向方面编程 (AOP) 通过提供另一种思考程序结构的方式来补充面向对象编程 (OOP)。OOP 中模块化的关键单元是类,而 AOP 中模块化的单元是方面。方面支持跨多种类型和对象的关注点(例如事务管理)的模块化。
AOP 在 Spring Framework 中用于
- 提供声明式企业服务。最重要的此类服务是 声明式事务管理。
- 让用户实现自定义方面,用 AOP 补充他们对 OOP 的使用。
AOP 概念
Aspect:跨多个类的关注点的模块化。事务管理是企业 Java 应用程序中横切关注点的一个很好的例子。在 Spring AOP 中,方面是通过使用常规类或使用 @Aspect注解注释的常规类(@AspectJ 样式)来实现的。
Join point 连接点:程序执行过程中的一个点,例如方法的执行或异常的处理。在 Spring AOP 中,一个连接点总是代表一个方法执行。
Advice 建议:方面在特定连接点采取的行动。不同类型的建议包括“周围”、“之前”和“之后”建议。(通知类型将在后面讨论。)包括 Spring 在内的许多 AOP 框架将通知建模为拦截器,并在连接点周围维护一个拦截器链。
Pointcut 切入点:匹配连接点的谓词。Advice 与切入点表达式相关联,并在与切入点匹配的任何连接点处运行(例如,执行具有特定名称的方法)。切入点表达式匹配的连接点的概念是 AOP 的核心,Spring 默认使用 AspectJ 切入点表达式语言。
Introduction 简介:代表一个类型声明额外的方法或字段。Spring AOP 允许您向任何建议的对象引入新接口(和相应的实现)。例如,您可以使用介绍使 bean 实现 IsModified 接口,以简化缓存。(介绍在 AspectJ 社区中称为类型间声明。)
Target object 目标对象:一个或多个方面建议的对象。也称为“建议对象”。由于 Spring AOP 是使用运行时代理实现的,因此该对象始终是代理对象。
AOP proxy AOP 代理:由 AOP 框架创建的对象,用于实现方面协定(建议方法执行等)。在 Spring Framework 中,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 使用 JDK 动态代理或 CGLIB 为给定的目标对象创建代理。JDK 动态代理内置在 JDK 中,而 CGLIB 是一个通用的开源类定义库(spring-core)
如果要代理的目标对象实现了至少一个接口,则使用 JDK 动态代理。目标类型实现的所有接口都被代理。如果目标对象没有实现任何接口,则创建一个 CGLIB 代理。
如果您想强制使用 CGLIB 代理(例如,代理为目标对象定义的每个方法,而不仅仅是那些由其接口实现的方法),您可以这样做。但是,您应该考虑以下问题:
- 使用 CGLIB,final不能建议方法,因为它们不能在运行时生成的子类中被覆盖。
- 从 Spring 4.0 开始,代理对象的构造函数不再被调用两次,因为 CGLIB 代理实例是通过 Objenesis 创建的。仅当您的 JVM 不允许绕过构造函数时,您可能会看到来自 Spring 的 AOP 支持的双重调用和相应的调试日志条目。