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));