目录
Spring AOP
编辑AOP适用场景
AOP的组成
连接点(Join Point)
切点(Pointcut)
通知(Advice)
Spring AOP的实现
添加依赖
定义切面与切点
切点表达式的说明
定义相关的通知
AOP(Aspect Oriented Programming)是面向切面编程,是一种设计思想.对某一类的事情集中处理
就像是在页面需要在用户为登录状态这个前提下才能进行后序的操作,一个项目肯定不止有一个页面,那么对于每一个不同页面的方法我们都要去加入判断用户登录状态的程序,在后期维护和修改的时候花费的成本会比较大.
对于这些需要去完成同一件事的不同的方法/类,我们就可以把他们集中起来进行配置处理.
适用于对于功能统一且被运用比较多的就可以考虑用AOP进行统一的处理.
1.页面登录状态的验证
2.统一的日志记录
3.统一的方法执行时间的计算
...
AOP就像给某一个方法/类在特定的位置新增添了一些功能.
但这些功能是我们程序员本来就想让他们实现的,但是每一个方法都实现花费的成本就比较多,所以集中起来进行统一的配置.
AOP中有四个关键词:切面(Aspect),切点(Pointcut),连接点(Join Point)以及通知(Advice)
下面对四个关键词进行展开,并简单说明AOP的流程.
连接点是应用执行过程中能够插入切面的一个点.这个点可以是方法中的开头,抛出异常时或方法结束的之前或之后.
切点指的是通知要织入的具体位置.
(切点与连接点的关系图)
切面的工作被称为了通知.通知定义了切面的工作是什么,以及要工作的时间节点.
通知有着五种类型:
切面(Aspect)
切面是通知与切点的集合.其包含了工作的内容,执行的地点与执行的时间.
在Maven仓库中搜索AOP,选择
Maven Repository: org.springframework.boot » spring-boot-starter-aop (mvnrepository.com)
此处我选择的是2.7.x的版本
org.springframework.boot
spring-boot-starter-aop
2.7.8
在与启动类的同一个目录下,创建AOP包并创建一个对应的类,我们会将这个类定义为"切面"
@Aspect //切面的定义
@Component//还是要把此类注入到spring boot当中
public class UserAOP {
//切点的定义
//AspectJ表达式,来规定切点的范围
@Pointcut("execution(* com.example.demo.Controller.UserController.* (..))")
public void pointcut(){}
@Pointcut()
public void abcd(){} //@Pointcut注解下的方法都是无具体实现的空方法,作为@Pointcut标签的"载体"
@Before("pointcut()")//通知
public void doBefore(){
System.out.println("前置通知");
}
}
@Pointcut修饰的方法都不需要具体实现,只是作为标识的存在.因为切点可以很多个,就可以用被注解的方法名来区分并调用.
AspectJ表达式支持三种通配符
切点表达式由切点函数组成,其中 execution() 是最常⽤的切点函数,⽤来匹配⽅法,语法:
execution(<修饰符><返回类型><包.类.⽅法(参数)><异常>)
一般修饰符与异常两个参数可以省略.
修饰符:
返回类型:
包(包的路径):
类:
方法名:
参数:
示例:
"execution(* com.example.demo.Controller.UserController.* (..))":匹配对应Controller包中UserController类下的所有方法都可以作为切点.
通知的定义是被拦截的方法具体要执行的业务.像是前面所说的登录验证,在切点范围中的方法将要执行之前会被拦截下来,先进行登录验证.这个登录验证就是具体要执行的业务.
@Before("pointcut()")
public void doBefore(){
System.out.println("前置通知");
}
@After("pointcut()")
public void doAfter(){
System.out.println("后置通知");
}
@AfterReturning("pointcut()")
public void doAfterReturn(){
System.out.println("方法返回前发送的通知");
}
@AfterThrowing("pointcut()")
public void doAfterThrow(){
System.out.println("方法抛出异常前发送的通知");
}
//以上方法都是Around下的注解,Around更像是自定义模式,指定通知在哪里执行.
@Around("pointcut()")
public Object doAround(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
Object result = null;
System.out.println("哇哈哈哈");
result = proceedingJoinPoint.proceed();//调用被拦截的方法
System.out.println("wahahaha");
return result;
}
关于环绕通知的几个注意点: