AOP面向切面编程
AOP面向切面编程
JaronAOP的概念
1 | <dependency> |
面向切面编程:将很多重复的代码都归到一起,比如我想统计10个方法的执行时间,那么我就可以只写一份代码,套在10个方法上。
AOP核心概念
- 连接点:JoinPoint,可以被AOP控制的方法(暗含方法执行时的相关信息)
- 通知:Advice,指哪些重复的逻辑,也就是共性功能(最终体现为一个方法)
- 切入点:Pointcut,匹配连接点的条件,通知仅会在切入点方法执行时被应用
- 切面:Aspect,描述通知与切入点的对应关系(通知+切入点)
- 目标对象:Target,通知所应用的对象
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15//加入容器
//标识为AOP
public class TimeAspect {
//切入点表达式
public Object recordTime(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {//这个方法称为通知
long begin = System.currentTimeMillis();
Object object = proceedingJoinPoint.proceed(); // 调用原始方法
long end = System.currentTimeMillis();
Log.info(proceedingJoinPoint.getSignature() + "执行耗时: " + (end - begin) + "ms");
return object;
}
}
通知类型
- @Around:环绕通知,此注解标注的通知方法在目标方法前、后都被执行
- @Before:前置通知,此注解标注的通知方法在目标方法前被执行
- @After:后置通知,此注解标注的通知方法在目标方法后被执行,无论是否有异常都会执行
- @AfterReturning :返回后通知,此注解标注的通知方法在目标方法后被执行,有异常不会执行
- @AfterThrowing: 异常后通知,此注解标注的通知方法发生异常后执行
当我们想用多个通知时,并且切入点表达式一样,我们可以用@Pointcut进行抽取。
1 |
|
切入点表达式
execution
execution 主要根据方法的返回值、包名、类名、方法名、方法参数等信息来匹配,语法为:
execution(访问修饰符 返回值 包名.类名.方法名(方法参数) throws 异常)
访问修饰符:可省略(比如:public、protected)
包名.类名:可省略
throws 异常:可省略(注意是方法上声明抛出的异常,不是实际抛出的异常)
• 可以使用通配符描述切入点
*:单个独立的任意符号,可以通配任意返回值、包名、类名、方法名、任意类型的一个参数,也可以通配包、类、方法名的一部分
execution(* com.*.service.*.update*(*))
..:多个连续的任意符号,可以通配任意层级的包,或任意类型、任意个数的参数
execution(* com.savitar.. service.*(..))
@annotation
@annotation(注解全类名),通过在方法上自己加注解,就可以想匹配谁就匹配谁。
首先,定义一个自定义注解,例如 @LogExecutionTime:
1 |
|
创建一个切面类,使用 @Aspect 注解标记,并在其中定义拦截逻辑。例如,在方法执行前后记录日志:
1 |
|
被LogExecutionTime注解的方法都会被拦截
1 |
|
连接点
JoinPoint:这个接口提供了一系列方法来访问执行中的连接点的状态。一个连接点可以是一个方法的执行,一个异常的处理,一个字段的修改等。在Spring AOP中,连接点总是代表一个方法的执行。
ProceedingJoinPoint:这是
JoinPoint的一个子接口,它只用于环绕通知(Around Advice)。与JoinPoint相比,它多了一个方法proceed(),这个方法用于控制何时执行切入的方法。在环绕通知中,你可以在调用proceed()方法之前和之后添加额外的处理。
示例
假设我们有一个简单的服务类,我们想在其方法执行前后添加一些日志。
1 | public class SimpleService { |
