概述
AOP 意为面向特定的方法编程
一个例子来引入
@Slf4j
@Component
@Aspect //AOP类
public class TimeAspect {
@Around("execution(* com.sky.service.impl.*.*(..))")
public Object recordTime(ProceedingJoinPoint joinPoint) throws Throwable{
//记录开始时间
long beginTime = System.currentTimeMillis();
//调用原始方法运行
Object result = joinPoint.proceed();
//记录结束时间
long endTime = System.currentTimeMillis();
log.info("方法运行时间:{}",endTime - beginTime);
return result;
}
}
这个代码借助了AOP来统计了service层的接口或者类的运行时间,而不用修改原始代码。
AOP核心概念
连接点:JoinPoint,可以被AOP控制的办法,包含着方法执行时的相关信息
通知:Advice,指哪些重复的逻辑,也就是共性功能
切入点:PointCut,匹配连接点的条件,通知仅会在切入点方法执行时被应用
切面:Aspect,描述通知与切入点的对应关系
目标对象:Target,通知所应用的对象
通知类型
@Around:环绕通知,此注解标注的通知方法在目标方法前、后都被执行
@Before:前置通知,此注解标注的通知方法在目标方法前被执行
@After :后置通知,此注解标注的通知方法在目标方法后被执行,无论是否有异常都会执行
@AfterReturning:返回后通知,此注解标注的通知方法在目标方法后被执行,有异常不会执行
@AfterThrowing :异常后通知,此注解标注的通知方法发生异常后执行
通知顺序
目标方法前的通知方法:字母排名越靠前,越先执行
目标方法后的通知方法:字母排名越靠后,越先执行
切入点表达式
用来决定项目中的哪些方法需要加入通知
execution():根据方法的签名来匹配
语法是:execution(访问修饰符 返回值 包名.类名.方法名(方法参数)throws 异常)
可以省略异常、访问修饰符、包名.类名
通配符
* :单个独立的任意符号,可以通配任意返回值、包名、类名、方法名、任意类型的一个参数,也可以通配包、类、方法名的一部分
比如execution(*com.*.service.*.update*(*))
五个*号依次对应:任意类型的返回值、任意的第二级包、service下的任意的接口或者类、任意以update开头的方法并且是一个参数
.. :多个连续的任意符号,可以通配任意层级的包,或任意类型、任意个数的参数
主要用于匹配方法的任意个数的参数
@annotation 切入点表达式,用于匹配标识有特定注解的方法。
@annotation(全类名),然后再通知方法添加@类名 这个注解即可
连接点
在Spring中用JoinPoint抽象了连接点,用它可以获得方法执行时的相关信息,如目标类名、方法名、方法参数等。
对于 @Around 通知,获取连接点信息只能使用ProceedingJoinPoint
对于其他四种通知,获取连接点信息只能使用 JoinPoint,它是 ProceedingJoinPoint 的父类型
String className = joinPoint.getTarget().getclass().getName();//获取目标类名
Signature signature = joinPoint.getsignature();//获取目标方法签名
String methodName = joinPoint.getsignature().getName();//获取目标方法名
Object[]args = joinPoint.getArgs();//获取目标方法运行参数
Object result= joinPoint.proceed(); //放行目标方法
return result;