AOP 概念
让我们首先定义一些核心的AOP概念和术语。这些术语并非Spring所特有。不幸的是,AOP的术语并不特别直观易懂。然而,如果Spring使用自己的术语,反而会更加令人困惑。
-
方面(Aspect):一种横跨多个类的模块化关注点。事务管理是企业Java应用程序中典型的横切关注点(crosscutting concern)示例。在Spring AOP中,方面是通过使用普通类(基于模式的方法)或带有
@Aspect注解的普通类(@AspectJ风格)来实现的。 -
连接点(Join Point):程序执行过程中的某个点,例如方法的执行或异常的处理。在Spring AOP中,连接点始终代表方法执行。
-
通知(Advice):方面在特定连接点上执行的操作。通知有多种类型,包括“around”、“before”和“after”通知。(通知的类型将在后面讨论。)包括Spring在内的许多AOP框架都将通知建模为拦截器(interceptor),并在连接点周围维护一个拦截器链。
-
切点(Pointcut):用于匹配连接点的谓词。通知与一个切点表达式相关联,并在该切点表达式匹配的任何连接点上运行(例如,执行具有特定名称的方法)。切点表达式所匹配的连接点概念是AOP的核心,Spring默认使用AspectJ的切点表达式语言。
-
引入(Introduction):代表某个类型声明额外的方法或字段。Spring AOP允许你为任何被通知的对象引入新的接口(以及相应的实现)。例如,你可以利用引入让一个Bean实现
IsModified接口,以简化缓存功能。(在AspectJ社区中,引入被称为“类型间声明”(inter-type declaration)。) -
目标对象(Target Object):被一个或多个方面所通知的对象。也称为“被通知对象”(advised object)。由于Spring AOP是通过使用运行时代理(runtime proxies)来实现的,因此这个对象始终是一个被代理的对象。
-
AOP代理(AOP Proxy):由AOP框架创建的对象,用于实现方面的契约(如通知方法的执行等)。在Spring框架中,AOP代理可以是JDK动态代理(JDK dynamic proxy)或CGLIB代理(CGLIB proxy)。
-
织入(Weaving):将方面与其他应用程序类型或对象关联起来以创建被通知的对象。这可以在编译时(例如使用AspectJ编译器)、加载时或运行时完成。与其他纯Java AOP框架一样,Spring AOP在运行时执行织入操作。
Spring AOP包括以下类型的 Advice:
-
Before advice: 在连接点(join point)之前执行的建议,但这种建议没有能力阻止执行流程继续进行到该连接点(除非它抛出异常)。
-
After returning advice: 在连接点正常完成之后执行的建议(例如,如果方法在不抛出异常的情况下返回)。
-
After throwing advice: 如果方法通过抛出异常而退出,则会执行的建议。
-
After (finally) advice: 无论连接点以何种方式退出(正常返回还是异常退出),都会执行的建议。
-
Around advice: 包围连接点(如方法调用)的建议。这是最强大的建议类型。Around advice可以在方法调用前后执行自定义行为。它还负责决定是否继续执行到连接点,或者通过返回自己的返回值或抛出异常来简化被建议方法的执行过程。
“Around”建议是最通用类型的建议。由于Spring AOP(如同AspectJ一样)提供了多种类型的建议,我们建议您使用功能最简单但能够实现所需行为的那一种建议类型。例如,如果您只需要用方法的返回值来更新缓存,那么使用“after returning”建议就足够了,尽管“around”建议也能完成同样的任务。使用特定性最高的建议类型能够提供更简洁的编程模型,并且出错的可能性也更小。比如,在使用“around”建议时,您不需要调用JoinPoint上的proceed()方法,因此也就不存在调用失败的情况。
所有建议参数都是静态类型的,这样你就可以使用适当类型的建议参数(例如,方法执行返回值的类型),而不是Object数组。
由切点(pointcuts)匹配的连接点(join points)概念是AOP(面向切面编程)的关键,这也是AOP与那些仅提供拦截(interception)功能的旧技术之间的区别所在。切点使得Advice(切面逻辑)能够独立于面向对象的层次结构进行应用。例如,你可以对一组跨越多个对象的方法(比如服务层中的所有业务操作)应用一种“around”类型的Advice,以实现声明式的事务管理。