七、AOP
1. 概述
AOP(Aspect Oriented Programming):面向切面编程、面向方法编程,其实就是面向特定方法编程
场景:
- 案例部分功能运行较慢,定位执行耗时较长的业务方法,此时需要统计每个业务方法的执行耗时,也就是我们想在方法前面或者后面执行一些操作
- 记录操作日志
- 权限控制
- 事务管理
实现:
引入依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
主流实现是动态代理。SpringAOP是Spring框架的高级技术,旨在管理bean对象的过程中,主要通过底层的动态代理机制,对特定方法进行编程——运行的就是代理对象
@Slf4j
@Component
@Aspect // AOP类
public class TimeAspect {
// 加在哪些方法上
@Around("execution(* com.example.server.*.*(..))") // 切入点表达式
public Object recordTime(ProceedingJoinPoint jointPoint) throws Throwable {
// 1. 记录开始时间
long begin = System.currentTimeMillis();
// 2. 调用原始方法运行
Object result = jointPoint.proceed();
// 3. 记录结束时间,计算方法执行耗时
long end = System.currentTimeMillis();
log.info(jointPoint.getSignature() + "方法耗时:{}ms", end - begin);
return result;
}
}
核心概念:
- 连接点: JointPoint,可以被AOP控制的方法(暗含方法执行时的相关信息)——它覆盖的每一个方法都可以看作一个连接点
- 通知: Advice,重复的逻辑,也就是共性功能,体现为一个方法
- 切入点: PointCut,匹配连接点的条件,通知仅会在切入点方法执行时被应用
- 切面: Aspect,通知与切入点的对应关系(通知+切入点)
- 目标对象: Target,通知所应用的对象
2. 通知
2.1 通知类型
注意事项:
- Around如果代码执行出现异常,后半段代码也不会执行
- @Around环绕通知需要自己调用ProceedingJoinPoint.proceed()来让原始方法执行,其他通知不需要考虑目标方法执行
- @Around环绕通知方法的返回值必须指定Object,来接收原始方法的返回值
如果是public修饰的切入点,其他类中也能进行调用
2.2 通知顺序
切面类类名,before正序,after倒序
用@Order(数字)加在切面类上来控制顺序,前数字小的先执行,后数字小的后执行
3. 切入点表达式
切入点表达式: 描述切入点方法的一种表达式
作用: 主要用来决定项目中哪些方法需要加入通知
常见形式:
1)execution(…):根据方法的签名来匹配,多个可以使用逻辑运算符连接——常用
-
书写建议
-
- 所有业务方法名在命名时尽量规范,方便切入点表达式快速匹配。如:查询类方法都是find开头,更新类方法都是update开头
- 描述切入点方法通常基于接口描述,而不是直接描述实现类,增强扩展性
- 在满足业务需求的前提下,尽量缩小切入点的匹配范围
2)@annotation(…):根据注解匹配——不规则或不好描述的时候使用
自定义一个注解,在需要加切入点表达式的方法上加上自定义注解,@annotation(注解的全类名)
4. 连接点
可以在通知中获取连接点的相关信息——像反射部分
可以篡改目标方法执行的结果