Spring AOP 介绍
AOP 简介
AOP (Aspect Orient Programming),直译过来就是面向切面编程。AOP 是一种编程思想,是面向对象编程(OOP)的一种补充。
在 OOP 中,模块化的基本单位是类,而 AOP 中模块化的基本单位是切面。
Spring 中关于 AOP 的介绍:5. Aspect Oriented Programming with Spring
AOP 相关术语
术语 | 中文翻译 | 说明 |
---|---|---|
Aspect | 切面 | 切面是 Pointcut 和 Advice 的集合,一般单独作为一个类。在 Spring AOP 中,使用 @Aspect 注解来实现切面。 |
Joinpoint | 连接点 | 程序执行过程的一个点,例如一个方法的执行或一个异常的处理。在 Spring AOP 中,一个连接点总是代表一个方法的执行。 |
Advice | 增强 | 切面在连接点执行的动作。不同增强类型包含 “around”、”before”、”after”等增强。 |
Pointcut | 切点 | 可以插入增强的连接点。 |
Introduction | 引入 | 为一个类添加额外的方法或属性。Spring AOP 允许我们为目标对象引入新的接口(及对应的实现)。 |
Target object | 目标对象 | 由一个或多个切面增强的对象。也称为 “advised object”。由于 Spring AOP 是使用运行时代理来实现的,所以这个对象始终是一个被代理的对象。 |
AOP proxy | AOP代理 | AOP 创建的对象,用于实现切面规约(增强方法执行等)。在 Spring 中,AOP 代理是一个 JDK 动态代理或 CGLIB 代理。 |
Weaving | 织入 | 创建一个被增强对象的过程。 |
通过注解来配置 Spring AOP
Spring AOP 支持的切入点指示器
指示符 | 说明 |
---|---|
execution | 用于匹配方法执行连接点 |
within | 限制匹配特定类型的连接点 |
this | 限制匹配特定的连接点,Spring AOP 代理的 Bean 是指定类型的实例 |
target | 限制匹配特定的连接点,其中目标对象(被代码的应用对象)是指定类型的实例 |
args | 限制匹配参数为指定类型的连接点 |
@target | 限制匹配连接点特定的执行对象,这些对象对应的类要具备指定类型的注解 |
@args | 限制匹配传递的参数类型为指定类型的注解 |
@within | 限制匹配到指定注解所标注的类型中的连接点 |
@annotation | 限制匹配指定注解的连接点 |
例如,以下是使用 execution
指示器的一个例子:
execution(* com.lanweihong.aop.service.IEatService.eat(..))
使用 execution
指示器选择 IEatService
的 eat
方法,当 eat
方法执行时触发增强,方法表达式以 *
开头,表示返回任意类型的值。然后指定了全限定类名和方法 com.lanweihong.aop.service.IEatService.eat()
,对于方法参数,使用 ..
表示任意参数。
以下是一些通用切入点表达式用法的例子:
// 任意公共方法执行:
execution(public * *(..))
// 任何一个以 "set" 开头的方法执行:
execution(* set*(..))
// AccountService 接口定义的任意方法执行:
execution(* com.xyz.service.AccountService.*(..))
// 在 service 包中定义的任意方法执行:
execution(* com.xyz.service.*.*(..))
// 在 service 包及其子包中定义的任意方法执行:
execution(* com.xyz.service..*.*(..))
// 在 service 包的任意连接点(在Spring AOP中只是方法执行):
within(com.xyz.service.*)
// 在 service 包及其子包中的任意连接点(在Spring AOP中只是方法执行):
within(com.xyz.service..*)
// 实现了 AccountService 接口的代理对象的任意连接点(在Spring AOP中只是方法执行):
this(com.xyz.service.AccountService)
// 实现 AccountServic 接口的目标对象的任意连接点(在Spring AOP中只是方法执行):
target(com.xyz.service.AccountService)
// 任何一个只接受一个参数,并且运行时所传入的参数是 Serializable 接口的连接点(在Spring AOP中只是方法执行):
args(java.io.Serializable)
// 目标对象中有一个 `@Transactional` 注解的任意连接点 (在Spring AOP中只是方法执行):
@target(org.springframework.transaction.annotation.Transactional)
// 任何一个目标对象声明的类型有一个 @Transactional 注解的连接点 (在Spring AOP中只是方法执行):
@within(org.springframework.transaction.annotation.Transactional)
// 任何一个执行的方法有一个 @Transactional 注解的连接点 (在Spring AOP中只是方法执行):
@annotation(org.springframework.transaction.annotation.Transactional)
// 任何一个只接受一个参数,并且运行时所传入的参数类型具有 @Classified 注解的连接点(在Spring AOP中只是方法执行):
@args(com.xyz.security.Classified)
// 任何一个在名为 "tradeService" 的 Spring Bean 之上的连接点 (在Spring AOP中只是方法执行):
bean(tradeService)
// 任何一个在名字匹配通配符表达式 "*Service" 的 Spring Bean 之上的连接点 (在Spring AOP中只是方法执行):
bean(*Service)
对于多个匹配,我们可以使用连接符 &&
、||
、!
来表示 「且」、「或」、「非」的关系。对于使用 XML 配置时,使用 「and」、「or」、「not」 来表示。
示例:
// 匹配以 Service 或 ServiceImpl 结尾的 bean
bean(*Service || *ServiceImpl)
// 匹配名字以 Service 结尾, 并且在包 com.lanweihong.service 中的 bean
bean(*Service) && within(com.lanweihong.service.*)
// 匹配注解为 @AuthCheck 且在 service 包中的任意方法
annotation(com.lanweihong.annotation.AuthCheck) && execution(* com.lanweihong.service.*.*(..))
Spring AOP 中的 5 种增强类型
增强(Advice) | 说明 |
---|---|
Before | 在连接点(方法)之前执行 |
AfterReturning | 在连接点(方法)成功执行之后执行 |
AfterThrowing | 在连接点(方法)抛出异常后执行 |
After | 在连接点(方法)之后执行,无论方法执行成功或抛出异常 |
Around | 在连接点(方法)调用的前后执行,就是将切入点包起来执行。这是一种最强大的增强类型,它可以在方法调用前后执行自定义行为。 |
从 Spring 5.2.7 后,Advice 执行的顺序如下图所示: