AOP:面向切面编程,本质是面向特定方法编程
- 引入依赖:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
示例:记录方法运行耗时
package com.diaryback.aop;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;
@Slf4j
@Component
@Aspect //声明AOP类
public class TimeAspect {
@Around("execution(* com.diaryback.controller.*.*(..))") //切入点表达式
public Object recordTime(ProceedingJoinPoint joinPoint) throws Throwable {
//记录开始时间
long begin = System.currentTimeMillis();
//调用目标方法
Object result = joinPoint.proceed();
//记录结束时间
long end = System.currentTimeMillis();
log.info(joinPoint.getSignature() + "方法执行耗时:{}ms", end - begin);
return result;
}
}
连接点JoinPoint:可以被AOP控制的方法(暗含方法执行时的信息)
通知Advice:共性的功能,最终被提取为一个方法
切入点PointCut:匹配连接点的条件,通知仅会在切入点方法执行时被调用。通常用切入点表达式来描述
切面Aspect:通知+切入点
目标对象Target:通知所应用的对象
环绕通知
环绕通知必须调用参数jointPoint.proceed()让原始方法执行,且必须指定返回值为Object来接收原始方法的返回值
通知顺序
当多个切面类匹配到同一个目标方法时都会执行,before通知类名排名越靠前的先执行,after通知类名排名越靠后越先执行
可以用@Order注解控制执行顺序。before方法数字小的先执行,after方法数字小的后执行
切入点表达式
- execution
execution(访问修饰符? 返回值 包名.类名.?方法名(方法参数) throws 异常?)
通配符:*可以通配任意返回值,包名,,方法名,任意类型参数,也可以通配包、类、方法名的一部分
..:可以匹配任意层级的包或任意类型任意个数的参数
可以使用&& || !组合比较复杂的切入点表达式
- annotation
用于匹配标识有特定注解的方法
连接点
- 对于Around通知,获取连接点信息只能用ProceedingJoinPoint
- 对于其他四种通知获取连接点信息只能用JoinPoint,是ProceedingJoinPoint的父类型
//获取目标对象的类名
String className = joinPoint.getTarget().getClass().getName();
log.info("className: {}", className);
//获取目标对象的方法名
String methodName = joinPoint.getSignature().getName();
log.info("methodName: {}", methodName);
//获取目标对象的参数
Object[] args = joinPoint.getArgs();
log.info("args: {}", Arrays.toString(args));