SpringAOP
AOP
AOP(Aspect-Oriented Programming,面向切面编程)是一种编程范式,它通过将横切关注点(cross-cutting concern)从业务逻辑中分离出来,从而提高代码的可维护性和可重用性。横切关注点是指那些在多个模块或类中都需要关注的通用功能,例如日志记录、性能监控、安全检查、事务管理等。
AOP的核心概念
- 连接点(Join Point):
程序执行过程中的某个特定点,例如方法调用、异常抛出等。 - 切点(Pointcut):
定义了一组连接点,用于指定在哪些连接点上应用切面。 - 通知(Advice):
在切点处执行的代码块,用于实现横切关注点的逻辑。通知可以分为以下几种类型:- 前置通知(Before Advice):在连接点之前执行。
- 后置通知(After Advice):在连接点之后执行。
- 返回通知(After Returning Advice):在连接点正常返回后执行。
- 异常通知(After Throwing Advice):在连接点抛出异常时执行。
- 环绕通知(Around Advice):在连接点之前和之后都执行。
- 切面(Aspect):
将切点和通知组合在一起的模块,用于定义横切关注点的逻辑。 - 织入(Weaving):
将切面应用到目标对象的过程,可以发生在编译时、类加载时或运行时。
AOP的优势
- 代码复用:
将横切关注点集中在一个地方实现,避免重复代码。 - 代码可维护性:
修改横切关注点时,只需修改切面,无需修改多个模块。 - 代码简洁性:
业务逻辑代码更加专注于核心功能,不被横切关注点干扰。
SpringAOP
基于代理模式实现,适用于Spring框架中的应用。
使用SpringAOP,需要在pom.xml文件中导入依赖:
1 | <dependency> |
编写AOP程序
在aop方法实现类前加上注解@Component和@Aspect
例如:
1 | // 使用 @Aspect 注解声明这是一个切面 |
通知类型
- @Around: 环绕通知。该注解标注的通知方法在目标方法执行前、后都被执行
- @Before:前置通知。该注解标注的通知方法在目标方法执行之前被执行
- @After:后置通知。该注解标注的通知方法在目标方法执行后被执行,且无论是否有异常都会执行
- @AfterReturning:返回后通知。该注解标注的通知方法在目标方法执行后被执行,但是目标方法有异常时不会执行
- @AfterThrowing:异常后通知。该注解标注的通知方法在发生异常后执行
通知顺序
- 当多个切面类的切入点都匹配到了目标方法时,多个通知方法的执行顺序
- 不同切面类中,默认按照切面类的类名字母顺序排序:
- 目标方法执行前的通知方法:字母排名靠前的先执行
- 目标方法执行后的通知方法:字母排名靠后的先执行
- 在切面类上加注解@Order(数字)可以控制顺序
- 目标方法执行前的通知方法:数字小的先执行
- 目标方法执行后的通知方法:数字大的先执行
- 不同切面类中,默认按照切面类的类名字母顺序排序:
切入点表达式
- 描述切入点方法的一种表达式,主要用来决定项目中哪些方法需要加入通知
- 形式:
- execution(……):根据方法的返回值、包名、类名、方法名、方法参数等来匹配
- 语法:execution(【访问修饰符】 返回值 【包名.类名】.方法名(方法参数)【 throws 异常】)
- 注:带【】的可以省略
- 异常是方法上声明抛出的异常,不是实际抛出的异常
- 通配符:
- *:单个独立的任意符号,可以匹配任意返回值、包名、类名、方法名、任意类型的一个参数,也可以通配包、类、方法名字中的一部分
- .. :多个连续的任意符号,可以通配任意层级的包、或任意类型、任意个数的参数
- 可以用||、&&、!来组合不同的切入点表达式
- @annotation(……):用于匹配标识有特定注解的方法
- 用法:自定义一个注解,在定义时加上@Retention()指定注解生效时间,和@Target()指定注解作用范围;在要通知的方法前加上自定义的注解,然后在@PointCut()中使用注解@annotation(自定义的注解的全类名)
- execution(……):根据方法的返回值、包名、类名、方法名、方法参数等来匹配
- 形式:
连接点
- Spring中用JoinPoint抽象了连接点,用它可以获得方法执行时的相关信息,如目标类名、方法名、方法参数等
- @Around通知,获取连接点信息只能用ProceedingJoinPoint
- 其他四种通知类型,获取连接点信息只能用JoinPoint(ProceedingJoinPoint的父类型)
完整的SpringAOP实例
1、目标类
1 | public class UserService { |
2、切面类
1 | //声明该类是一个切面类 |
3、配置类
1 |
|
4、测试类
1 | public class TestAOP { |
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来源 cantutas!