目录
- [Spring AOP](#Spring AOP)
Spring AOP
AOP是什么
- Aspect Oriented Programminig(面向切面编程)
- 切面 指的是某一类特定问题,比如说登录拦截器,就是对"登录校验",这一类问题的统一处理
- 所以,拦截器是AOP的一种应用
- AOP是一种思想,是对某一类事情的集中处理
什么是Spring AOP
- AOP是一种思想,它的实现方法有很多,有Spring AOP,也有AspectJ ,CGLIB等。
AOP可以做到在不改动这些原始方法的基础上,针对特定的方法进行功能的增强
AOP的作用:在程序运行期间在不修改源代码的基础上,对已有的方法进行增强(无侵入性:解耦)
AOP实际开发流程
1. 引入依赖
在pom.xml文件中添加配置
xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
2. 编写AOP程序
业务:记录Controller中每个方法的执行时间
java
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
@Aspect
@Component
public class TimeAspect {
/**
* 记录⽅法耗时
*/
@Around("execution(* com.example.demo.controller.*.*(..))")
public Object recordTime(ProceedingJoinPoint pjp) throws Throwable {
//记录⽅法执⾏开始时间
long begin = System.currentTimeMillis();
//执⾏原始⽅法
Object result = pjp.proceed();
//记录⽅法执⾏结束时间
long end = System.currentTimeMillis();
//记录⽅法执⾏耗时
log.info(pjp.getSignature() + "执⾏耗时: {}ms", end - begin);
return result;
}
}
Spring AOP详解
- @Aspect: 标识这是一个切面类
- @Around:环绕通知,在目标方法执行前后都会被执行。
- ProceedingJoinPoint.proceed() 让原始方法执行
Spring AOP中的核心概念
- 切点(Pointcut)
提供一组规则,告诉程序对哪些方法来进行增强
-
连接点
满足切点表达式规则的方法
例如切点表达式:英雄联盟全部射手
连接点:希维尔,艾希等各个射手
-
通知(Advice)
具体要做的工作
-
切面(Aspect)
切面 = 切点 + 通知
切面所在的类,一般称为切面类
Spring AOP的通知类型
六种类型
上⾯我们讲了什么是通知, 接下来学习通知的类型. @Around 就是其中⼀种通知类型, 表⽰环绕通知.
Spring中AOP的通知类型有以下⼏种:
• @Around: 环绕通知, 此注解标注的通知⽅法在⽬标⽅法前, 后都被执⾏
• @Before: 前置通知, 此注解标注的通知⽅法在⽬标⽅法前被执⾏
• @After: 后置通知, 此注解标注的通知⽅法在⽬标⽅法后被执⾏, ⽆论是否有异常都会执⾏
• @AfterReturning: 返回后通知, 此注解标注的通知⽅法在⽬标⽅法后被执⾏, 有异常不会执⾏
• @AfterThrowing: 异常后通知, 此注解标注的通知⽅法发⽣异常后执⾏
程序发生异常的情况下:
- @AfterReturning 标识的通知方法不会执行,@AfterThrowing 标识的通知方法执行
- @Around环绕通知中原始方法调用时有异常,通知中的环绕后的代码逻辑也不会在执行了
注意事项:
- 环绕通知⽅法的返回值, 必须指定为Object, 来接收原始⽅法的返回值, 否则原始⽅法执⾏完毕, 是获取不到返回值的.
- @Around 环绕通知需要调用ProceedingJoinPoint.proceed() 来让原始⽅法执⾏, 其他通知不需要考虑⽬标⽅法执⾏.
- 一个切面类可以用多个切点
@PointCut
上⾯代码存在⼀个问题, 就是存在⼤量重复的切点表达式 execution(* com.example.demo.controller.. (...)) , Spring提供了 @PointCut 注解, 把公共的切点表达式提取出来, 需要⽤到时引⽤该切⼊点表达式即可.
上述代码就可以修改为:
java
@Aspect
@Component
public class AspectDemo {
//定义切点(公共的切点表达式)
@Pointcut("execution(* com.example.demo.controller.*.*(..))")
private void pt(){}
//前置通知
@Before("pt()")
public void doBefore() {
//...代码省略
}
//后置通知
@After("pt()")
public void doAfter() {
//...代码省略
}
//返回后通知
@AfterReturning("pt()")
public void doAfterReturning() {
//...代码省略
}
//抛出异常后通知
@AfterThrowing("pt()")
public void doAfterThrowing() {
//...代码省略
}
//添加环绕通知
@Around("pt()")
public Object doAround(ProceedingJoinPoint joinPoint) throws Throwable {
//...代码省略
}
}
@Order(切面优先级)
存在多个切⾯类时, 默认按照切⾯类的类名字⺟排序:
• @Before 通知:字⺟排名靠前的先执⾏
• @After 通知:字⺟排名靠前的后执⾏
但这种⽅式不⽅便管理, 我们的类名更多还是具备⼀定含义的.
Spring 给我们提供了⼀个新的注解, 来控制这些切⾯通知的执⾏顺序: @Order
该注解标识的切⾯类, 执⾏顺序如下:
• @Before 通知:数字越⼩先执⾏
• @After 通知:数字越⼤先执⾏